KickJava   Java API By Example, From Geeks To Geeks.

Java > Open Source Codes > net > sf > saxon > event > CDATAFilter


1 package net.sf.saxon.event;
2 import net.sf.saxon.charcode.CharacterSet;
3 import net.sf.saxon.charcode.CharacterSetFactory;
4 import net.sf.saxon.om.FastStringBuffer;
5 import net.sf.saxon.om.XMLChar;
6 import net.sf.saxon.tinytree.CharSlice;
7 import net.sf.saxon.trans.XPathException;
8
9 import javax.xml.transform.OutputKeys JavaDoc;
10 import java.util.Properties JavaDoc;
11 import java.util.Stack JavaDoc;
12 import java.util.StringTokenizer JavaDoc;
13
14 /**
15 * CDATAFilter: This ProxyEmitter converts character data to CDATA sections,
16 * if the character data belongs to one of a set of element types to be handled this way.
17 *
18 * @author Michael Kay
19 */

20
21
22 public class CDATAFilter extends ProxyReceiver {
23
24     private FastStringBuffer buffer = new FastStringBuffer(256);
25     private Stack JavaDoc stack = new Stack JavaDoc();
26     private int[] nameList; // fingerprints of cdata elements
27
private CharacterSet characterSet;
28
29     /**
30     * Set the properties for this CDATA filter
31     */

32
33     public void setOutputProperties (Properties JavaDoc details)
34     throws XPathException {
35         nameList = getCdataElements(details);
36         characterSet = CharacterSetFactory.getCharacterSet(details, getPipelineConfiguration().getController());
37     }
38
39     /**
40     * Output element start tag
41     */

42
43     public void startElement(int nameCode, int typeCode, int locationId, int properties) throws XPathException {
44         flush(buffer);
45         stack.push(new Integer JavaDoc(nameCode & 0xfffff));
46         super.startElement(nameCode, typeCode, locationId, properties);
47     }
48
49     /**
50     * Output element end tag
51     */

52
53     public void endElement() throws XPathException {
54         flush(buffer);
55         stack.pop();
56         super.endElement();
57     }
58
59     /**
60     * Output a processing instruction
61     */

62
63     public void processingInstruction(String JavaDoc target, CharSequence JavaDoc data, int locationId, int properties) throws XPathException {
64         flush(buffer);
65         super.processingInstruction(target, data, locationId, properties);
66     }
67
68     /**
69     * Output character data
70     */

71
72     public void characters(CharSequence JavaDoc chars, int locationId, int properties) throws XPathException {
73
74         if ((properties & ReceiverOptions.DISABLE_ESCAPING) == 0) {
75             buffer.append(chars.toString());
76         } else {
77             // if the user requests disable-output-escaping, this overrides the CDATA request. We end
78
// the CDATA section and output the characters as supplied.
79
flush(buffer);
80             super.characters(chars, locationId, properties);
81         }
82     }
83
84     /**
85     * Output a comment
86     */

87
88     public void comment(CharSequence JavaDoc chars, int locationId, int properties) throws XPathException {
89         flush(buffer);
90         super.comment(chars, locationId, properties);
91     }
92
93
94     /**
95     * Flush the buffer containing accumulated character data,
96     * generating it as CDATA where appropriate
97     */

98
99     public void flush(FastStringBuffer buffer) throws XPathException {
100         boolean cdata;
101         int end = buffer.length();
102         if (end==0) return;
103
104         if (stack.isEmpty()) {
105             cdata = false; // text is not part of any element
106
} else {
107             int fprint = ((Integer JavaDoc)stack.peek()).intValue();
108             cdata = isCDATA(fprint);
109         }
110
111         if (cdata) {
112
113             // Check that the buffer doesn't include a character not available in the current
114
// encoding
115

116             int start = 0;
117             int k = 0;
118             while ( k < end ) {
119                 int next = buffer.charAt(k);
120                 int skip = 1;
121                 if (XMLChar.isHighSurrogate((char)next)) {
122                     next = XMLChar.supplemental((char)next, buffer.charAt(k+1));
123                     skip = 2;
124                 }
125                 if (characterSet.inCharset(next)) {
126                     k++;
127                 } else {
128
129                     // flush out the preceding characters as CDATA
130

131                     char[] array = new char[k-start];
132                     buffer.getChars(start, k, array, 0);
133                     flushCDATA(array, k-start);
134
135                     while (k < end) {
136                         // output consecutive non-encodable characters
137
// before restarting the CDATA section
138
//super.characters(CharBuffer.wrap(buffer, k, k+skip), 0, 0);
139
super.characters(buffer.subSequence(k, k+skip), 0, 0);
140                                 // was: (..., ReceiverOptions.DISABLE_ESCAPING);
141
k += skip;
142                         next = buffer.charAt(k);
143                         skip = 1;
144                         if (XMLChar.isHighSurrogate((char)next)) {
145                             next = XMLChar.supplemental((char)next, buffer.charAt(k+1));
146                             skip = 2;
147                         }
148                         if (characterSet.inCharset(next)) {
149                             break;
150                         }
151                     }
152                     start=k;
153                 }
154             }
155             char[] rest = new char[end-start];
156             buffer.getChars(start, end, rest, 0);
157             flushCDATA(rest, end-start);
158
159         } else {
160 // char[] array = new char[end];
161
// buffer.getChars(0, end, array, 0);
162
// super.characters(CharBuffer.wrap(array, 0, end), 0, 0);
163
super.characters(buffer, 0, 0);
164         }
165
166         buffer.setLength(0);
167
168     }
169
170     /**
171     * Output an array as a CDATA section. At this stage we have checked that all the characters
172     * are OK, but we haven't checked that there is no "]]>" sequence in the data
173     */

174
175     private void flushCDATA(char[] array, int len) throws XPathException {
176         super.characters("<![CDATA[", 0, ReceiverOptions.DISABLE_ESCAPING);
177
178         // Check that the character data doesn't include the substring "]]>"
179

180         int i=0;
181         int doneto=0;
182         while (i<len-2) {
183             if (array[i]==']' && array[i+1]==']' && array[i+2]=='>') {
184                 super.characters(new CharSlice(array, doneto, i+2-doneto), 0, ReceiverOptions.DISABLE_ESCAPING);
185                 super.characters("]]><![CDATA[", 0, ReceiverOptions.DISABLE_ESCAPING);
186                 doneto=i+2;
187             }
188             i++;
189         }
190         super.characters(new CharSlice(array, doneto, len-doneto), 0, ReceiverOptions.DISABLE_ESCAPING);
191         super.characters("]]>", 0, ReceiverOptions.DISABLE_ESCAPING);
192     }
193
194
195     /**
196     * See if a particular element is a CDATA element
197     */

198
199     private boolean isCDATA(int fingerprint) {
200         for (int i=0; i<nameList.length; i++) {
201             if (nameList[i]==fingerprint) return true;
202         }
203         return false;
204     }
205
206     /**
207     * Extract the list of CDATA elements from the output properties
208     */

209
210     private int[] getCdataElements(Properties JavaDoc details) {
211         String JavaDoc cdata = details.getProperty(OutputKeys.CDATA_SECTION_ELEMENTS);
212         if (cdata==null) {
213             // this doesn't happen, but there's no harm allowing for it
214
return new int[0];
215         }
216         // first count the number of names in the list
217
int count=0;
218         StringTokenizer JavaDoc st1 = new StringTokenizer JavaDoc(cdata);
219         while (st1.hasMoreTokens()) {
220             st1.nextToken();
221             count++;
222         }
223         int[] array = new int[count];
224         count = 0;
225         StringTokenizer JavaDoc st2 = new StringTokenizer JavaDoc(cdata);
226         while (st2.hasMoreTokens()) {
227             String JavaDoc expandedName = st2.nextToken();
228             array[count++] = getNamePool().getFingerprintForExpandedName(expandedName);
229         }
230         return array;
231     }
232
233 };
234
235 //
236
// The contents of this file are subject to the Mozilla Public License Version 1.0 (the "License");
237
// you may not use this file except in compliance with the License. You may obtain a copy of the
238
// License at http://www.mozilla.org/MPL/
239
//
240
// Software distributed under the License is distributed on an "AS IS" basis,
241
// WITHOUT WARRANTY OF ANY KIND, either express or implied.
242
// See the License for the specific language governing rights and limitations under the License.
243
//
244
// The Original Code is: all this file.
245
//
246
// The Initial Developer of the Original Code is Michael H. Kay.
247
//
248
// Portions created by (your name) are Copyright (C) (your legal entity). All Rights Reserved.
249
//
250
// Contributor(s): none.
251
//
252

253
Popular Tags