1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17 package org.apache.jetspeed.util;
18
19
20 import java.io.InputStream;
21 import java.io.PrintWriter;
22 import java.io.Reader;
23 import java.io.UnsupportedEncodingException;
24 import java.util.Vector;
25
26
27 import org.xml.sax.AttributeList;
28 import org.xml.sax.HandlerBase;
29 import org.xml.sax.InputSource;
30 import org.xml.sax.Parser;
31 import org.xml.sax.SAXException;
32 import org.xml.sax.SAXParseException;
33 import org.xml.sax.helpers.ParserFactory;
34
35
36 import org.apache.jetspeed.services.logging.JetspeedLogFactoryService;
37 import org.apache.jetspeed.services.logging.JetspeedLogger;
38
39 /***
40 This class is used to either strip and/or insert PIs in a XML document.
41 It uses SAX-1 API and outputs text to an
42 output stream.
43 WARNING: This behavior will be modified in the future.
44
45 @author <A HREF="mailto:raphael@apache.org">Raphaël Luta</A>
46 @version $Id: SAXPIFilter.java,v 1.8 2004/02/23 03:23:42 jford Exp $
47 */
48 public class SAXPIFilter extends HandlerBase
49 {
50 /***
51 * Static initialization of the logger for this class
52 */
53 private static final JetspeedLogger logger = JetspeedLogFactoryService.getLogger(SAXPIFilter.class.getName());
54
55 private static final String DEFAULT_PARSER_NAME = "org.apache.xerces.parsers.SAXParser";
56
57 protected PrintWriter out=new PrintWriter(System.out);
58
59 private String pi;
60
61 private boolean stripExistingPI;
62
63 private Vector pis = new Vector();
64
65 /***
66 Creates of simple parser which outputs its document to the PrintWriter passed
67 as arguments.
68 In this mode the parser may be used as a simple well-formedness checker.
69
70 @param outPW the printWriter where to output parsed data
71 */
72 public SAXPIFilter(PrintWriter outPW) throws UnsupportedEncodingException {
73 this(outPW,false,null);
74 }
75
76 /***
77 In this mode the parser may be used as a simple well-formedness checker or a PI
78 stripper.
79
80 @param outPW the printWriter where to output parsed data
81 @param strip configure the parser to strip PIs if strip is true
82 */
83 public SAXPIFilter(PrintWriter outPW, boolean strip) throws UnsupportedEncodingException {
84 this( outPW, strip, null );
85 }
86
87 /***
88 In this mode the parser can strip existing PIs and insert new ones just after
89 the document declaration
90
91 @param outPW the printWriter where to output parsed data
92 @param strip configure the parser to strip PIs if strip is true
93 @param PI string reprensenting the PI to be output after the document declaration
94 */
95 public SAXPIFilter(PrintWriter outPW, boolean strip, String PI) throws UnsupportedEncodingException {
96 this.out=outPW;
97 this.stripExistingPI=strip;
98 this.pi=PI;
99 }
100
101 /***
102 Get all permitted processing instructions
103 */
104 public String[] getProcessingInstructions() {
105
106 String[] ins = new String[ pis.size() ];
107 pis.copyInto( ins );
108 return ins;
109
110 }
111
112 public void addProcessingInstruction(String pi) {
113 this.pis.addElement( pi );
114 }
115
116
117 /***
118 Parse and output the content of the URL given as parameter.
119
120 @param uri URL where to fetch the document to be parsed
121 */
122 public void print(String uri) {
123
124 try {
125 HandlerBase handler = this;
126
127 Parser parser = ParserFactory.makeParser(DEFAULT_PARSER_NAME);
128 parser.setDocumentHandler(handler);
129 parser.setErrorHandler(handler);
130 parser.parse(uri);
131 }
132 catch (Exception e) {
133 logger.error("Exception", e);
134 }
135
136 }
137
138 /***
139 Parse and output the content of the stream
140
141 @param in a content InputStream
142 */
143 public void print(InputStream in) {
144
145 try {
146 HandlerBase handler = this;
147
148 Parser parser = ParserFactory.makeParser(DEFAULT_PARSER_NAME);
149 parser.setDocumentHandler(handler);
150 parser.setErrorHandler(handler);
151 parser.parse(new InputSource(in));
152 }
153 catch (Exception e) {
154 logger.error("Exception", e);
155 }
156
157 }
158
159 /***
160 Parse and output the content of the reader
161
162 @param in a content Reader
163 */
164 public void print(Reader in) {
165
166 try {
167 HandlerBase handler = this;
168
169 Parser parser = ParserFactory.makeParser(DEFAULT_PARSER_NAME);
170 parser.setDocumentHandler(handler);
171 parser.setErrorHandler(handler);
172 parser.parse(new InputSource(in));
173 }
174 catch (Exception e) {
175 logger.error("Exception", e);
176 }
177
178 }
179
180 /***
181 SAX Handler implementation
182 */
183 public void processingInstruction(String target, String data) {
184
185
186 if ( ! stripExistingPI ) {
187 out.print( makeSAXPI( target, data ) );
188 } else {
189
190
191
192
193 if ( target.equals("cocoon-process") ) {
194
195 this.addProcessingInstruction( makeSAXPI( target, data ) );
196
197 }
198
199 }
200
201 }
202
203 private String makeSAXPI( String target, String data ) {
204
205 StringBuffer buffer = new StringBuffer();
206 buffer.append("<?");
207 buffer.append( target );
208 if (data != null && data.length() > 0) {
209 buffer.append(' ');
210 buffer.append(data);
211 }
212 buffer.append("?>");
213
214 return buffer.toString();
215 }
216
217
218
219 /***
220 SAX Handler implementation
221 */
222 public void startDocument() {
223
224 if ( pi != null ) {
225 out.print( pi );
226 }
227
228 }
229
230 /***
231 SAX Handler implementation
232 */
233 public void startElement(String name, AttributeList attrs) {
234
235 out.print('<');
236 out.print(name);
237 if (attrs != null) {
238 int len = attrs.getLength();
239 for (int i = 0; i < len; i++) {
240 out.print(' ');
241 out.print(attrs.getName(i));
242 out.print("=\"");
243 out.print(normalize(attrs.getValue(i)));
244 out.print('"');
245 }
246 }
247 out.print('>');
248
249 }
250
251 /***
252 SAX Handler implementation
253 */
254 public void characters(char ch[], int start, int length) {
255
256 out.print(normalize(new String(ch, start, length)));
257
258 }
259
260 /***
261 SAX Handler implementation
262 */
263 public void ignorableWhitespace(char ch[], int start, int length) {
264
265 characters(ch, start, length);
266
267 }
268
269 /***
270 SAX Handler implementation
271 */
272 public void endElement(String name) {
273
274 out.print("</");
275 out.print(name);
276 out.print('>');
277
278 }
279
280 /***
281 SAX Handler implementation
282 */
283 public void endDocument() {
284
285 out.flush();
286
287 }
288
289 /***
290 SAX Handler implementation
291 */
292 public void warning(SAXParseException ex) {
293 System.err.println("[Warning] "+
294 getLocationString(ex)+": "+
295 ex.getMessage());
296 }
297
298 /***
299 SAX Handler implementation
300 */
301 public void error(SAXParseException ex) {
302 System.err.println("[Error] "+
303 getLocationString(ex)+": "+
304 ex.getMessage());
305 }
306
307 /***
308 SAX Handler implementation
309 */
310 public void fatalError(SAXParseException ex) throws SAXException {
311 System.err.println("[Fatal Error] "+
312 getLocationString(ex)+": "+
313 ex.getMessage());
314 throw ex;
315 }
316
317 /***
318 Retrieves the error location in the input stream
319 */
320 private String getLocationString(SAXParseException ex) {
321 StringBuffer str = new StringBuffer();
322
323 String systemId = ex.getSystemId();
324 if (systemId != null) {
325 int index = systemId.lastIndexOf('/');
326 if (index != -1)
327 systemId = systemId.substring(index + 1);
328 str.append(systemId);
329 }
330 str.append(':');
331 str.append(ex.getLineNumber());
332 str.append(':');
333 str.append(ex.getColumnNumber());
334
335 return str.toString();
336
337 }
338
339 /***
340 Escapes characters data
341 */
342 protected String normalize(String s) {
343 StringBuffer str = new StringBuffer();
344
345 int len = (s != null) ? s.length() : 0;
346 for (int i = 0; i < len; i++) {
347 char ch = s.charAt(i);
348 switch (ch) {
349 case '<': {
350 str.append("<");
351 break;
352 }
353 case '>': {
354 str.append(">");
355 break;
356 }
357 case '&': {
358 str.append("&");
359 break;
360 }
361 case '"': {
362 str.append(""");
363 break;
364 }
365 default: {
366 str.append(ch);
367 }
368 }
369 }
370
371 return str.toString();
372
373 }
374
375 }