0
|
1 /*--
|
|
2
|
|
3 $Id: SAXOutputter.java,v 1.40 2007/11/10 05:29:01 jhunter Exp $
|
|
4
|
|
5 Copyright (C) 2000-2007 Jason Hunter & Brett McLaughlin.
|
|
6 All rights reserved.
|
|
7
|
|
8 Redistribution and use in source and binary forms, with or without
|
|
9 modification, are permitted provided that the following conditions
|
|
10 are met:
|
|
11
|
|
12 1. Redistributions of source code must retain the above copyright
|
|
13 notice, this list of conditions, and the following disclaimer.
|
|
14
|
|
15 2. Redistributions in binary form must reproduce the above copyright
|
|
16 notice, this list of conditions, and the disclaimer that follows
|
|
17 these conditions in the documentation and/or other materials
|
|
18 provided with the distribution.
|
|
19
|
|
20 3. The name "JDOM" must not be used to endorse or promote products
|
|
21 derived from this software without prior written permission. For
|
|
22 written permission, please contact <request_AT_jdom_DOT_org>.
|
|
23
|
|
24 4. Products derived from this software may not be called "JDOM", nor
|
|
25 may "JDOM" appear in their name, without prior written permission
|
|
26 from the JDOM Project Management <request_AT_jdom_DOT_org>.
|
|
27
|
|
28 In addition, we request (but do not require) that you include in the
|
|
29 end-user documentation provided with the redistribution and/or in the
|
|
30 software itself an acknowledgement equivalent to the following:
|
|
31 "This product includes software developed by the
|
|
32 JDOM Project (http://www.jdom.org/)."
|
|
33 Alternatively, the acknowledgment may be graphical using the logos
|
|
34 available at http://www.jdom.org/images/logos.
|
|
35
|
|
36 THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESSED OR IMPLIED
|
|
37 WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
|
|
38 OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
|
|
39 DISCLAIMED. IN NO EVENT SHALL THE JDOM AUTHORS OR THE PROJECT
|
|
40 CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
|
|
41 SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
|
|
42 LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF
|
|
43 USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
|
|
44 ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
|
|
45 OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT
|
|
46 OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
|
|
47 SUCH DAMAGE.
|
|
48
|
|
49 This software consists of voluntary contributions made by many
|
|
50 individuals on behalf of the JDOM Project and was originally
|
|
51 created by Jason Hunter <jhunter_AT_jdom_DOT_org> and
|
|
52 Brett McLaughlin <brett_AT_jdom_DOT_org>. For more information
|
|
53 on the JDOM Project, please see <http://www.jdom.org/>.
|
|
54
|
|
55 */
|
|
56
|
|
57 package org.jdom.output;
|
|
58
|
|
59 import java.io.*;
|
|
60 import java.lang.reflect.*;
|
|
61 import java.util.*;
|
|
62
|
|
63 import org.jdom.*;
|
|
64 import org.xml.sax.*;
|
|
65 import org.xml.sax.ext.*;
|
|
66 import org.xml.sax.helpers.*;
|
|
67
|
|
68 /**
|
|
69 * Outputs a JDOM document as a stream of SAX2 events.
|
|
70 * <p>
|
|
71 * Most ContentHandler callbacks are supported. Both
|
|
72 * <code>ignorableWhitespace()</code> and <code>skippedEntity()</code> have not
|
|
73 * been implemented. The <code>{@link JDOMLocator}</code> class returned by
|
|
74 * <code>{@link #getLocator}</code> exposes the current node being operated
|
|
75 * upon.
|
|
76 * <p>
|
|
77 * At this time, it is not possible to access notations and unparsed entity
|
|
78 * references in a DTD from JDOM. Therefore, <code>DTDHandler</code> callbacks
|
|
79 * have not been implemented yet.
|
|
80 * <p>
|
|
81 * The <code>ErrorHandler</code> callbacks have not been implemented, since
|
|
82 * these are supposed to be invoked when the document is parsed and at this
|
|
83 * point the document exists in memory and is known to have no errors. </p>
|
|
84 *
|
|
85 * @version $Revision: 1.40 $, $Date: 2007/11/10 05:29:01 $
|
|
86 * @author Brett McLaughlin
|
|
87 * @author Jason Hunter
|
|
88 * @author Fred Trimble
|
|
89 * @author Bradley S. Huffman
|
|
90 */
|
|
91 public class SAXOutputter {
|
|
92
|
|
93 private static final String CVS_ID =
|
|
94 "@(#) $RCSfile: SAXOutputter.java,v $ $Revision: 1.40 $ $Date: 2007/11/10 05:29:01 $ $Name: jdom_1_1_1 $";
|
|
95
|
|
96 /** Shortcut for SAX namespaces core feature */
|
|
97 private static final String NAMESPACES_SAX_FEATURE =
|
|
98 "http://xml.org/sax/features/namespaces";
|
|
99
|
|
100 /** Shortcut for SAX namespace-prefixes core feature */
|
|
101 private static final String NS_PREFIXES_SAX_FEATURE =
|
|
102 "http://xml.org/sax/features/namespace-prefixes";
|
|
103
|
|
104 /** Shortcut for SAX validation core feature */
|
|
105 private static final String VALIDATION_SAX_FEATURE =
|
|
106 "http://xml.org/sax/features/validation";
|
|
107
|
|
108 /** Shortcut for SAX-ext. lexical handler property */
|
|
109 private static final String LEXICAL_HANDLER_SAX_PROPERTY =
|
|
110 "http://xml.org/sax/properties/lexical-handler";
|
|
111
|
|
112 /** Shortcut for SAX-ext. declaration handler property */
|
|
113 private static final String DECL_HANDLER_SAX_PROPERTY =
|
|
114 "http://xml.org/sax/properties/declaration-handler";
|
|
115
|
|
116 /**
|
|
117 * Shortcut for SAX-ext. lexical handler alternate property.
|
|
118 * Although this property URI is not the one defined by the SAX
|
|
119 * "standard", some parsers use it instead of the official one.
|
|
120 */
|
|
121 private static final String LEXICAL_HANDLER_ALT_PROPERTY =
|
|
122 "http://xml.org/sax/handlers/LexicalHandler";
|
|
123
|
|
124 /** Shortcut for SAX-ext. declaration handler alternate property */
|
|
125 private static final String DECL_HANDLER_ALT_PROPERTY =
|
|
126 "http://xml.org/sax/handlers/DeclHandler";
|
|
127
|
|
128 /**
|
|
129 * Array to map JDOM attribute type (as entry index) to SAX
|
|
130 * attribute type names.
|
|
131 */
|
|
132 private static final String[] attrTypeToNameMap = new String[] {
|
|
133 "CDATA", // Attribute.UNDEFINED_ATTRIBUTE, as per SAX 2.0 spec.
|
|
134 "CDATA", // Attribute.CDATA_TYPE
|
|
135 "ID", // Attribute.ID_TYPE
|
|
136 "IDREF", // Attribute.IDREF_TYPE
|
|
137 "IDREFS", // Attribute.IDREFS_TYPE
|
|
138 "ENTITY", // Attribute.ENTITY_TYPE
|
|
139 "ENTITIES", // Attribute.ENTITIES_TYPE
|
|
140 "NMTOKEN", // Attribute.NMTOKEN_TYPE
|
|
141 "NMTOKENS", // Attribute.NMTOKENS_TYPE
|
|
142 "NOTATION", // Attribute.NOTATION_TYPE
|
|
143 "NMTOKEN", // Attribute.ENUMERATED_TYPE, as per SAX 2.0 spec.
|
|
144 };
|
|
145
|
|
146 /** registered <code>ContentHandler</code> */
|
|
147 private ContentHandler contentHandler;
|
|
148
|
|
149 /** registered <code>ErrorHandler</code> */
|
|
150 private ErrorHandler errorHandler;
|
|
151
|
|
152 /** registered <code>DTDHandler</code> */
|
|
153 private DTDHandler dtdHandler;
|
|
154
|
|
155 /** registered <code>EntityResolver</code> */
|
|
156 private EntityResolver entityResolver;
|
|
157
|
|
158 /** registered <code>LexicalHandler</code> */
|
|
159 private LexicalHandler lexicalHandler;
|
|
160
|
|
161 /** registered <code>DeclHandler</code> */
|
|
162 private DeclHandler declHandler;
|
|
163
|
|
164 /**
|
|
165 * Whether to report attribute namespace declarations as xmlns attributes.
|
|
166 * Defaults to <code>false</code> as per SAX specifications.
|
|
167 *
|
|
168 * @see <a href="http://www.megginson.com/SAX/Java/namespaces.html">
|
|
169 * SAX namespace specifications</a>
|
|
170 */
|
|
171 private boolean declareNamespaces = false;
|
|
172
|
|
173 /**
|
|
174 * Whether to report DTD events to DeclHandlers and LexicalHandlers.
|
|
175 * Defaults to <code>true</code>.
|
|
176 */
|
|
177 private boolean reportDtdEvents = true;
|
|
178
|
|
179 /**
|
|
180 * A SAX Locator that points at the JDOM node currently being
|
|
181 * outputted.
|
|
182 */
|
|
183 private JDOMLocator locator = null;
|
|
184
|
|
185 /**
|
|
186 * This will create a <code>SAXOutputter</code> without any
|
|
187 * registered handler. The application is then responsible for
|
|
188 * registering them using the <code>setXxxHandler()</code> methods.
|
|
189 */
|
|
190 public SAXOutputter() {
|
|
191 }
|
|
192
|
|
193 /**
|
|
194 * This will create a <code>SAXOutputter</code> with the
|
|
195 * specified <code>ContentHandler</code>.
|
|
196 *
|
|
197 * @param contentHandler contains <code>ContentHandler</code>
|
|
198 * callback methods
|
|
199 */
|
|
200 public SAXOutputter(ContentHandler contentHandler) {
|
|
201 this(contentHandler, null, null, null, null);
|
|
202 }
|
|
203
|
|
204 /**
|
|
205 * This will create a <code>SAXOutputter</code> with the
|
|
206 * specified SAX2 handlers. At this time, only <code>ContentHandler</code>
|
|
207 * and <code>EntityResolver</code> are supported.
|
|
208 *
|
|
209 * @param contentHandler contains <code>ContentHandler</code>
|
|
210 * callback methods
|
|
211 * @param errorHandler contains <code>ErrorHandler</code> callback methods
|
|
212 * @param dtdHandler contains <code>DTDHandler</code> callback methods
|
|
213 * @param entityResolver contains <code>EntityResolver</code>
|
|
214 * callback methods
|
|
215 */
|
|
216 public SAXOutputter(ContentHandler contentHandler,
|
|
217 ErrorHandler errorHandler,
|
|
218 DTDHandler dtdHandler,
|
|
219 EntityResolver entityResolver) {
|
|
220 this(contentHandler, errorHandler, dtdHandler, entityResolver, null);
|
|
221 }
|
|
222
|
|
223 /**
|
|
224 * This will create a <code>SAXOutputter</code> with the
|
|
225 * specified SAX2 handlers. At this time, only <code>ContentHandler</code>
|
|
226 * and <code>EntityResolver</code> are supported.
|
|
227 *
|
|
228 * @param contentHandler contains <code>ContentHandler</code>
|
|
229 * callback methods
|
|
230 * @param errorHandler contains <code>ErrorHandler</code> callback methods
|
|
231 * @param dtdHandler contains <code>DTDHandler</code> callback methods
|
|
232 * @param entityResolver contains <code>EntityResolver</code>
|
|
233 * callback methods
|
|
234 * @param lexicalHandler contains <code>LexicalHandler</code> callbacks.
|
|
235 */
|
|
236 public SAXOutputter(ContentHandler contentHandler,
|
|
237 ErrorHandler errorHandler,
|
|
238 DTDHandler dtdHandler,
|
|
239 EntityResolver entityResolver,
|
|
240 LexicalHandler lexicalHandler) {
|
|
241 this.contentHandler = contentHandler;
|
|
242 this.errorHandler = errorHandler;
|
|
243 this.dtdHandler = dtdHandler;
|
|
244 this.entityResolver = entityResolver;
|
|
245 this.lexicalHandler = lexicalHandler;
|
|
246 }
|
|
247
|
|
248 /**
|
|
249 * This will set the <code>ContentHandler</code>.
|
|
250 *
|
|
251 * @param contentHandler contains <code>ContentHandler</code>
|
|
252 * callback methods.
|
|
253 */
|
|
254 public void setContentHandler(ContentHandler contentHandler) {
|
|
255 this.contentHandler = contentHandler;
|
|
256 }
|
|
257
|
|
258 /**
|
|
259 * Returns the registered <code>ContentHandler</code>.
|
|
260 *
|
|
261 * @return the current <code>ContentHandler</code> or
|
|
262 * <code>null</code> if none was registered.
|
|
263 */
|
|
264 public ContentHandler getContentHandler() {
|
|
265 return this.contentHandler;
|
|
266 }
|
|
267
|
|
268 /**
|
|
269 * This will set the <code>ErrorHandler</code>.
|
|
270 *
|
|
271 * @param errorHandler contains <code>ErrorHandler</code> callback methods.
|
|
272 */
|
|
273 public void setErrorHandler(ErrorHandler errorHandler) {
|
|
274 this.errorHandler = errorHandler;
|
|
275 }
|
|
276
|
|
277 /**
|
|
278 * Return the registered <code>ErrorHandler</code>.
|
|
279 *
|
|
280 * @return the current <code>ErrorHandler</code> or
|
|
281 * <code>null</code> if none was registered.
|
|
282 */
|
|
283 public ErrorHandler getErrorHandler() {
|
|
284 return this.errorHandler;
|
|
285 }
|
|
286
|
|
287 /**
|
|
288 * This will set the <code>DTDHandler</code>.
|
|
289 *
|
|
290 * @param dtdHandler contains <code>DTDHandler</code> callback methods.
|
|
291 */
|
|
292 public void setDTDHandler(DTDHandler dtdHandler) {
|
|
293 this.dtdHandler = dtdHandler;
|
|
294 }
|
|
295
|
|
296 /**
|
|
297 * Return the registered <code>DTDHandler</code>.
|
|
298 *
|
|
299 * @return the current <code>DTDHandler</code> or
|
|
300 * <code>null</code> if none was registered.
|
|
301 */
|
|
302 public DTDHandler getDTDHandler() {
|
|
303 return this.dtdHandler;
|
|
304 }
|
|
305
|
|
306 /**
|
|
307 * This will set the <code>EntityResolver</code>.
|
|
308 *
|
|
309 * @param entityResolver contains EntityResolver callback methods.
|
|
310 */
|
|
311 public void setEntityResolver(EntityResolver entityResolver) {
|
|
312 this.entityResolver = entityResolver;
|
|
313 }
|
|
314
|
|
315 /**
|
|
316 * Return the registered <code>EntityResolver</code>.
|
|
317 *
|
|
318 * @return the current <code>EntityResolver</code> or
|
|
319 * <code>null</code> if none was registered.
|
|
320 */
|
|
321 public EntityResolver getEntityResolver() {
|
|
322 return this.entityResolver;
|
|
323 }
|
|
324
|
|
325 /**
|
|
326 * This will set the <code>LexicalHandler</code>.
|
|
327 *
|
|
328 * @param lexicalHandler contains lexical callback methods.
|
|
329 */
|
|
330 public void setLexicalHandler(LexicalHandler lexicalHandler) {
|
|
331 this.lexicalHandler = lexicalHandler;
|
|
332 }
|
|
333
|
|
334 /**
|
|
335 * Return the registered <code>LexicalHandler</code>.
|
|
336 *
|
|
337 * @return the current <code>LexicalHandler</code> or
|
|
338 * <code>null</code> if none was registered.
|
|
339 */
|
|
340 public LexicalHandler getLexicalHandler() {
|
|
341 return this.lexicalHandler;
|
|
342 }
|
|
343
|
|
344 /**
|
|
345 * This will set the <code>DeclHandler</code>.
|
|
346 *
|
|
347 * @param declHandler contains declaration callback methods.
|
|
348 */
|
|
349 public void setDeclHandler(DeclHandler declHandler) {
|
|
350 this.declHandler = declHandler;
|
|
351 }
|
|
352
|
|
353 /**
|
|
354 * Return the registered <code>DeclHandler</code>.
|
|
355 *
|
|
356 * @return the current <code>DeclHandler</code> or
|
|
357 * <code>null</code> if none was registered.
|
|
358 */
|
|
359 public DeclHandler getDeclHandler() {
|
|
360 return this.declHandler;
|
|
361 }
|
|
362
|
|
363 /**
|
|
364 * Returns whether attribute namespace declarations shall be reported as
|
|
365 * "xmlns" attributes.
|
|
366 *
|
|
367 * @return whether attribute namespace declarations shall be reported as
|
|
368 * "xmlns" attributes.
|
|
369 */
|
|
370 public boolean getReportNamespaceDeclarations() {
|
|
371 return declareNamespaces;
|
|
372 }
|
|
373
|
|
374 /**
|
|
375 * This will define whether attribute namespace declarations shall be
|
|
376 * reported as "xmlns" attributes. This flag defaults to <code>false</code>
|
|
377 * and behaves as the "namespace-prefixes" SAX core feature.
|
|
378 *
|
|
379 * @param declareNamespaces whether attribute namespace declarations
|
|
380 * shall be reported as "xmlns" attributes.
|
|
381 */
|
|
382 public void setReportNamespaceDeclarations(boolean declareNamespaces) {
|
|
383 this.declareNamespaces = declareNamespaces;
|
|
384 }
|
|
385
|
|
386 /**
|
|
387 * Returns whether DTD events will be reported.
|
|
388 *
|
|
389 * @return whether DTD events will be reported
|
|
390 */
|
|
391 public boolean getReportDTDEvents() {
|
|
392 return reportDtdEvents;
|
|
393 }
|
|
394
|
|
395 /**
|
|
396 * This will define whether to report DTD events to SAX DeclHandlers
|
|
397 * and LexicalHandlers if these handlers are registered and the
|
|
398 * document to output includes a DocType declaration.
|
|
399 *
|
|
400 * @param reportDtdEvents whether to notify DTD events.
|
|
401 */
|
|
402 public void setReportDTDEvents(boolean reportDtdEvents) {
|
|
403 this.reportDtdEvents = reportDtdEvents;
|
|
404 }
|
|
405
|
|
406 /**
|
|
407 * This will set the state of a SAX feature.
|
|
408 * <p>
|
|
409 * All XMLReaders are required to support setting to true and to false.
|
|
410 * </p>
|
|
411 * <p>
|
|
412 * SAXOutputter currently supports the following SAX core features:
|
|
413 * <dl>
|
|
414 * <dt><code>http://xml.org/sax/features/namespaces</code></dt>
|
|
415 * <dd><strong>description:</strong> <code>true</code> indicates
|
|
416 * namespace URIs and unprefixed local names for element and
|
|
417 * attribute names will be available</dd>
|
|
418 * <dd><strong>access:</strong> read/write, but always
|
|
419 * <code>true</code>!</dd>
|
|
420 * <dt><code>http://xml.org/sax/features/namespace-prefixes</code></dt>
|
|
421 * <dd><strong>description:</strong> <code>true</code> indicates
|
|
422 * XML 1.0 names (with prefixes) and attributes (including xmlns*
|
|
423 * attributes) will be available</dd>
|
|
424 * <dd><strong>access:</strong> read/write</dd>
|
|
425 * <dt><code>http://xml.org/sax/features/validation</code></dt>
|
|
426 * <dd><strong>description:</strong> controls whether SAXOutputter
|
|
427 * is reporting DTD-related events; if <code>true</code>, the
|
|
428 * DocType internal subset will be parsed to fire DTD events</dd>
|
|
429 * <dd><strong>access:</strong> read/write, defaults to
|
|
430 * <code>true</code></dd>
|
|
431 * </dl>
|
|
432 * </p>
|
|
433 *
|
|
434 * @param name <code>String</code> the feature name, which is a
|
|
435 * fully-qualified URI.
|
|
436 * @param value <code>boolean</code> the requested state of the
|
|
437 * feature (true or false).
|
|
438 *
|
|
439 * @throws SAXNotRecognizedException when SAXOutputter does not
|
|
440 * recognize the feature name.
|
|
441 * @throws SAXNotSupportedException when SAXOutputter recognizes
|
|
442 * the feature name but cannot set the requested value.
|
|
443 */
|
|
444 public void setFeature(String name, boolean value)
|
|
445 throws SAXNotRecognizedException, SAXNotSupportedException {
|
|
446 if (NS_PREFIXES_SAX_FEATURE.equals(name)) {
|
|
447 // Namespace prefix declarations.
|
|
448 this.setReportNamespaceDeclarations(value);
|
|
449 }
|
|
450 else {
|
|
451 if (NAMESPACES_SAX_FEATURE.equals(name)) {
|
|
452 if (value != true) {
|
|
453 // Namespaces feature always supported by SAXOutputter.
|
|
454 throw new SAXNotSupportedException(name);
|
|
455 }
|
|
456 // Else: true is OK!
|
|
457 }
|
|
458 else {
|
|
459 if (VALIDATION_SAX_FEATURE.equals(name)) {
|
|
460 // Report DTD events.
|
|
461 this.setReportDTDEvents(value);
|
|
462 }
|
|
463 else {
|
|
464 // Not a supported feature.
|
|
465 throw new SAXNotRecognizedException(name);
|
|
466 }
|
|
467 }
|
|
468 }
|
|
469 }
|
|
470
|
|
471 /**
|
|
472 * This will look up the value of a SAX feature.
|
|
473 *
|
|
474 * @param name <code>String</code> the feature name, which is a
|
|
475 * fully-qualified URI.
|
|
476 * @return <code>boolean</code> the current state of the feature
|
|
477 * (true or false).
|
|
478 *
|
|
479 * @throws SAXNotRecognizedException when SAXOutputter does not
|
|
480 * recognize the feature name.
|
|
481 * @throws SAXNotSupportedException when SAXOutputter recognizes
|
|
482 * the feature name but determine its value at this time.
|
|
483 */
|
|
484 public boolean getFeature(String name)
|
|
485 throws SAXNotRecognizedException, SAXNotSupportedException {
|
|
486 if (NS_PREFIXES_SAX_FEATURE.equals(name)) {
|
|
487 // Namespace prefix declarations.
|
|
488 return (this.declareNamespaces);
|
|
489 }
|
|
490 else {
|
|
491 if (NAMESPACES_SAX_FEATURE.equals(name)) {
|
|
492 // Namespaces feature always supported by SAXOutputter.
|
|
493 return (true);
|
|
494 }
|
|
495 else {
|
|
496 if (VALIDATION_SAX_FEATURE.equals(name)) {
|
|
497 // Report DTD events.
|
|
498 return (this.reportDtdEvents);
|
|
499 }
|
|
500 else {
|
|
501 // Not a supported feature.
|
|
502 throw new SAXNotRecognizedException(name);
|
|
503 }
|
|
504 }
|
|
505 }
|
|
506 }
|
|
507
|
|
508 /**
|
|
509 * This will set the value of a SAX property.
|
|
510 * This method is also the standard mechanism for setting extended
|
|
511 * handlers.
|
|
512 * <p>
|
|
513 * SAXOutputter currently supports the following SAX properties:
|
|
514 * <dl>
|
|
515 * <dt><code>http://xml.org/sax/properties/lexical-handler</code></dt>
|
|
516 * <dd><strong>data type:</strong>
|
|
517 * <code>org.xml.sax.ext.LexicalHandler</code></dd>
|
|
518 * <dd><strong>description:</strong> An optional extension handler for
|
|
519 * lexical events like comments.</dd>
|
|
520 * <dd><strong>access:</strong> read/write</dd>
|
|
521 * <dt><code>http://xml.org/sax/properties/declaration-handler</code></dt>
|
|
522 * <dd><strong>data type:</strong>
|
|
523 * <code>org.xml.sax.ext.DeclHandler</code></dd>
|
|
524 * <dd><strong>description:</strong> An optional extension handler for
|
|
525 * DTD-related events other than notations and unparsed entities.</dd>
|
|
526 * <dd><strong>access:</strong> read/write</dd>
|
|
527 * </dl>
|
|
528 * </p>
|
|
529 *
|
|
530 * @param name <code>String</code> the property name, which is a
|
|
531 * fully-qualified URI.
|
|
532 * @param value <code>Object</code> the requested value for the property.
|
|
533 *
|
|
534 * @throws SAXNotRecognizedException when SAXOutputter does not recognize
|
|
535 * the property name.
|
|
536 * @throws SAXNotSupportedException when SAXOutputter recognizes the
|
|
537 * property name but cannot set the requested value.
|
|
538 */
|
|
539 public void setProperty(String name, Object value)
|
|
540 throws SAXNotRecognizedException, SAXNotSupportedException {
|
|
541 if ((LEXICAL_HANDLER_SAX_PROPERTY.equals(name)) ||
|
|
542 (LEXICAL_HANDLER_ALT_PROPERTY.equals(name))) {
|
|
543 this.setLexicalHandler((LexicalHandler)value);
|
|
544 }
|
|
545 else {
|
|
546 if ((DECL_HANDLER_SAX_PROPERTY.equals(name)) ||
|
|
547 (DECL_HANDLER_ALT_PROPERTY.equals(name))) {
|
|
548 this.setDeclHandler((DeclHandler)value);
|
|
549 }
|
|
550 else {
|
|
551 throw new SAXNotRecognizedException(name);
|
|
552 }
|
|
553 }
|
|
554 }
|
|
555
|
|
556 /**
|
|
557 * This will look up the value of a SAX property.
|
|
558 *
|
|
559 * @param name <code>String</code> the property name, which is a
|
|
560 * fully-qualified URI.
|
|
561 * @return <code>Object</code> the current value of the property.
|
|
562 *
|
|
563 * @throws SAXNotRecognizedException when SAXOutputter does not recognize
|
|
564 * the property name.
|
|
565 * @throws SAXNotSupportedException when SAXOutputter recognizes the
|
|
566 * property name but cannot determine its value at this time.
|
|
567 */
|
|
568 public Object getProperty(String name)
|
|
569 throws SAXNotRecognizedException, SAXNotSupportedException {
|
|
570 if ((LEXICAL_HANDLER_SAX_PROPERTY.equals(name)) ||
|
|
571 (LEXICAL_HANDLER_ALT_PROPERTY.equals(name))) {
|
|
572 return this.getLexicalHandler();
|
|
573 }
|
|
574 else {
|
|
575 if ((DECL_HANDLER_SAX_PROPERTY.equals(name)) ||
|
|
576 (DECL_HANDLER_ALT_PROPERTY.equals(name))) {
|
|
577 return this.getDeclHandler();
|
|
578 }
|
|
579 else {
|
|
580 throw new SAXNotRecognizedException(name);
|
|
581 }
|
|
582 }
|
|
583 }
|
|
584
|
|
585
|
|
586 /**
|
|
587 * This will output the <code>JDOM Document</code>, firing off the
|
|
588 * SAX events that have been registered.
|
|
589 *
|
|
590 * @param document <code>JDOM Document</code> to output.
|
|
591 *
|
|
592 * @throws JDOMException if any error occurred.
|
|
593 */
|
|
594 public void output(Document document) throws JDOMException {
|
|
595 if (document == null) {
|
|
596 return;
|
|
597 }
|
|
598
|
|
599 // contentHandler.setDocumentLocator()
|
|
600 documentLocator(document);
|
|
601
|
|
602 // contentHandler.startDocument()
|
|
603 startDocument();
|
|
604
|
|
605 // Fire DTD events
|
|
606 if (this.reportDtdEvents) {
|
|
607 dtdEvents(document);
|
|
608 }
|
|
609
|
|
610 // Handle root element, as well as any root level
|
|
611 // processing instructions and comments
|
|
612 Iterator i = document.getContent().iterator();
|
|
613 while (i.hasNext()) {
|
|
614 Object obj = i.next();
|
|
615
|
|
616 // update locator
|
|
617 locator.setNode(obj);
|
|
618
|
|
619 if (obj instanceof Element) {
|
|
620 // process root element and its content
|
|
621 element(document.getRootElement(), new NamespaceStack());
|
|
622 }
|
|
623 else if (obj instanceof ProcessingInstruction) {
|
|
624 // contentHandler.processingInstruction()
|
|
625 processingInstruction((ProcessingInstruction) obj);
|
|
626 }
|
|
627 else if (obj instanceof Comment) {
|
|
628 // lexicalHandler.comment()
|
|
629 comment(((Comment) obj).getText());
|
|
630 }
|
|
631 }
|
|
632
|
|
633 // contentHandler.endDocument()
|
|
634 endDocument();
|
|
635 }
|
|
636
|
|
637 /**
|
|
638 * This will output a list of JDOM nodes as a document, firing
|
|
639 * off the SAX events that have been registered.
|
|
640 * <p>
|
|
641 * <strong>Warning</strong>: This method may output ill-formed XML
|
|
642 * documents if the list contains top-level objects that are not
|
|
643 * legal at the document level (e.g. Text or CDATA nodes, multiple
|
|
644 * Element nodes, etc.). Thus, it should only be used to output
|
|
645 * document portions towards ContentHandlers capable of accepting
|
|
646 * such ill-formed documents (such as XSLT processors).</p>
|
|
647 *
|
|
648 * @param nodes <code>List</code> of JDOM nodes to output.
|
|
649 *
|
|
650 * @throws JDOMException if any error occurred.
|
|
651 *
|
|
652 * @see #output(org.jdom.Document)
|
|
653 */
|
|
654 public void output(List nodes) throws JDOMException {
|
|
655 if ((nodes == null) || (nodes.size() == 0)) {
|
|
656 return;
|
|
657 }
|
|
658
|
|
659 // contentHandler.setDocumentLocator()
|
|
660 documentLocator(null);
|
|
661
|
|
662 // contentHandler.startDocument()
|
|
663 startDocument();
|
|
664
|
|
665 // Process node list.
|
|
666 elementContent(nodes, new NamespaceStack());
|
|
667
|
|
668 // contentHandler.endDocument()
|
|
669 endDocument();
|
|
670 }
|
|
671
|
|
672 /**
|
|
673 * This will output a single JDOM element as a document, firing
|
|
674 * off the SAX events that have been registered.
|
|
675 *
|
|
676 * @param node the <code>Element</code> node to output.
|
|
677 *
|
|
678 * @throws JDOMException if any error occurred.
|
|
679 */
|
|
680 public void output(Element node) throws JDOMException {
|
|
681 if (node == null) {
|
|
682 return;
|
|
683 }
|
|
684
|
|
685 // contentHandler.setDocumentLocator()
|
|
686 documentLocator(null);
|
|
687
|
|
688 // contentHandler.startDocument()
|
|
689 startDocument();
|
|
690
|
|
691 // Output node.
|
|
692 elementContent(node, new NamespaceStack());
|
|
693
|
|
694 // contentHandler.endDocument()
|
|
695 endDocument();
|
|
696 }
|
|
697
|
|
698 /**
|
|
699 * This will output a list of JDOM nodes as a fragment of an XML
|
|
700 * document, firing off the SAX events that have been registered.
|
|
701 * <p>
|
|
702 * <strong>Warning</strong>: This method does not call the
|
|
703 * {@link ContentHandler#setDocumentLocator},
|
|
704 * {@link ContentHandler#startDocument} and
|
|
705 * {@link ContentHandler#endDocument} callbacks on the
|
|
706 * {@link #setContentHandler ContentHandler}. The user shall
|
|
707 * invoke these methods directly prior/after outputting the
|
|
708 * document fragments.</p>
|
|
709 *
|
|
710 * @param nodes <code>List</code> of JDOM nodes to output.
|
|
711 *
|
|
712 * @throws JDOMException if any error occurred.
|
|
713 *
|
|
714 * @see #outputFragment(org.jdom.Content)
|
|
715 */
|
|
716 public void outputFragment(List nodes) throws JDOMException {
|
|
717 if ((nodes == null) || (nodes.size() == 0)) {
|
|
718 return;
|
|
719 }
|
|
720
|
|
721 // Output node list as a document fragment.
|
|
722 elementContent(nodes, new NamespaceStack());
|
|
723 }
|
|
724
|
|
725 /**
|
|
726 * This will output a single JDOM nodes as a fragment of an XML
|
|
727 * document, firing off the SAX events that have been registered.
|
|
728 * <p>
|
|
729 * <strong>Warning</strong>: This method does not call the
|
|
730 * {@link ContentHandler#setDocumentLocator},
|
|
731 * {@link ContentHandler#startDocument} and
|
|
732 * {@link ContentHandler#endDocument} callbacks on the
|
|
733 * {@link #setContentHandler ContentHandler}. The user shall
|
|
734 * invoke these methods directly prior/after outputting the
|
|
735 * document fragments.</p>
|
|
736 *
|
|
737 * @param node the <code>Content</code> node to output.
|
|
738 *
|
|
739 * @throws JDOMException if any error occurred.
|
|
740 *
|
|
741 * @see #outputFragment(java.util.List)
|
|
742 */
|
|
743 public void outputFragment(Content node) throws JDOMException {
|
|
744 if (node == null) {
|
|
745 return;
|
|
746 }
|
|
747
|
|
748 // Output single node as a document fragment.
|
|
749 elementContent(node, new NamespaceStack());
|
|
750 }
|
|
751
|
|
752 /**
|
|
753 * This parses a DTD declaration to fire the related events towards
|
|
754 * the registered handlers.
|
|
755 *
|
|
756 * @param document <code>JDOM Document</code> the DocType is to
|
|
757 * process.
|
|
758 */
|
|
759 private void dtdEvents(Document document) throws JDOMException {
|
|
760 DocType docType = document.getDocType();
|
|
761
|
|
762 // Fire DTD-related events only if handlers have been registered.
|
|
763 if ((docType != null) &&
|
|
764 ((dtdHandler != null) || (declHandler != null))) {
|
|
765
|
|
766 // Build a dummy XML document that only references the DTD...
|
|
767 String dtdDoc = new XMLOutputter().outputString(docType);
|
|
768
|
|
769 try {
|
|
770 // And parse it to fire DTD events.
|
|
771 createDTDParser().parse(new InputSource(
|
|
772 new StringReader(dtdDoc)));
|
|
773
|
|
774 // We should never reach this point as the document is
|
|
775 // ill-formed; it does not have any root element.
|
|
776 }
|
|
777 catch (SAXParseException e) {
|
|
778 // Expected exception: There's no root element in document.
|
|
779 }
|
|
780 catch (SAXException e) {
|
|
781 throw new JDOMException("DTD parsing error", e);
|
|
782 }
|
|
783 catch (IOException e) {
|
|
784 throw new JDOMException("DTD parsing error", e);
|
|
785 }
|
|
786 }
|
|
787 }
|
|
788
|
|
789 /**
|
|
790 * <p>
|
|
791 * This method tells you the line of the XML file being parsed.
|
|
792 * For an in-memory document, it's meaningless. The location
|
|
793 * is only valid for the current parsing lifecycle, but
|
|
794 * the document has already been parsed. Therefore, it returns
|
|
795 * -1 for both line and column numbers.
|
|
796 * </p>
|
|
797 *
|
|
798 * @param document JDOM <code>Document</code>.
|
|
799 */
|
|
800 private void documentLocator(Document document) {
|
|
801 locator = new JDOMLocator();
|
|
802 String publicID = null;
|
|
803 String systemID = null;
|
|
804
|
|
805 if (document != null) {
|
|
806 DocType docType = document.getDocType();
|
|
807 if (docType != null) {
|
|
808 publicID = docType.getPublicID();
|
|
809 systemID = docType.getSystemID();
|
|
810 }
|
|
811 }
|
|
812 locator.setPublicId(publicID);
|
|
813 locator.setSystemId(systemID);
|
|
814 locator.setLineNumber(-1);
|
|
815 locator.setColumnNumber(-1);
|
|
816
|
|
817 contentHandler.setDocumentLocator(locator);
|
|
818 }
|
|
819
|
|
820 /**
|
|
821 * <p>
|
|
822 * This method is always the second method of all callbacks in
|
|
823 * all handlers to be invoked (setDocumentLocator is always first).
|
|
824 * </p>
|
|
825 */
|
|
826 private void startDocument() throws JDOMException {
|
|
827 try {
|
|
828 contentHandler.startDocument();
|
|
829 }
|
|
830 catch (SAXException se) {
|
|
831 throw new JDOMException("Exception in startDocument", se);
|
|
832 }
|
|
833 }
|
|
834
|
|
835 /**
|
|
836 * <p>
|
|
837 * Always the last method of all callbacks in all handlers
|
|
838 * to be invoked.
|
|
839 * </p>
|
|
840 */
|
|
841 private void endDocument() throws JDOMException {
|
|
842 try {
|
|
843 contentHandler.endDocument();
|
|
844
|
|
845 // reset locator
|
|
846 locator = null;
|
|
847 }
|
|
848 catch (SAXException se) {
|
|
849 throw new JDOMException("Exception in endDocument", se);
|
|
850 }
|
|
851 }
|
|
852
|
|
853 /**
|
|
854 * <p>
|
|
855 * This will invoke the <code>ContentHandler.processingInstruction</code>
|
|
856 * callback when a processing instruction is encountered.
|
|
857 * </p>
|
|
858 *
|
|
859 * @param pi <code>ProcessingInstruction</code> containing target and data.
|
|
860 */
|
|
861 private void processingInstruction(ProcessingInstruction pi)
|
|
862 throws JDOMException {
|
|
863 if (pi != null) {
|
|
864 String target = pi.getTarget();
|
|
865 String data = pi.getData();
|
|
866 try {
|
|
867 contentHandler.processingInstruction(target, data);
|
|
868 }
|
|
869 catch (SAXException se) {
|
|
870 throw new JDOMException(
|
|
871 "Exception in processingInstruction", se);
|
|
872 }
|
|
873 }
|
|
874 }
|
|
875
|
|
876 /**
|
|
877 * <p>
|
|
878 * This will recursively invoke all of the callbacks for a particular
|
|
879 * element.
|
|
880 * </p>
|
|
881 *
|
|
882 * @param element <code>Element</code> used in callbacks.
|
|
883 * @param namespaces <code>List</code> stack of Namespaces in scope.
|
|
884 */
|
|
885 private void element(Element element, NamespaceStack namespaces)
|
|
886 throws JDOMException {
|
|
887 // used to check endPrefixMapping
|
|
888 int previouslyDeclaredNamespaces = namespaces.size();
|
|
889
|
|
890 // contentHandler.startPrefixMapping()
|
|
891 Attributes nsAtts = startPrefixMapping(element, namespaces);
|
|
892
|
|
893 // contentHandler.startElement()
|
|
894 startElement(element, nsAtts);
|
|
895
|
|
896 // handle content in the element
|
|
897 elementContent(element.getContent(), namespaces);
|
|
898
|
|
899 // update locator
|
|
900 if (locator != null) {
|
|
901 locator.setNode(element);
|
|
902 }
|
|
903
|
|
904 // contentHandler.endElement()
|
|
905 endElement(element);
|
|
906
|
|
907 // contentHandler.endPrefixMapping()
|
|
908 endPrefixMapping(namespaces, previouslyDeclaredNamespaces);
|
|
909 }
|
|
910
|
|
911 /**
|
|
912 * <p>
|
|
913 * This will invoke the <code>ContentHandler.startPrefixMapping</code>
|
|
914 * callback
|
|
915 * when a new namespace is encountered in the <code>Document</code>.
|
|
916 * </p>
|
|
917 *
|
|
918 * @param element <code>Element</code> used in callbacks.
|
|
919 * @param namespaces <code>List</code> stack of Namespaces in scope.
|
|
920 *
|
|
921 * @return <code>Attributes</code> declaring the namespaces local to
|
|
922 * <code>element</code> or <code>null</code>.
|
|
923 */
|
|
924 private Attributes startPrefixMapping(Element element,
|
|
925 NamespaceStack namespaces)
|
|
926 throws JDOMException {
|
|
927 AttributesImpl nsAtts = null; // The namespaces as xmlns attributes
|
|
928
|
|
929 Namespace ns = element.getNamespace();
|
|
930 if (ns != Namespace.XML_NAMESPACE) {
|
|
931 String prefix = ns.getPrefix();
|
|
932 String uri = namespaces.getURI(prefix);
|
|
933 if (!ns.getURI().equals(uri)) {
|
|
934 namespaces.push(ns);
|
|
935 nsAtts = this.addNsAttribute(nsAtts, ns);
|
|
936 try {
|
|
937 contentHandler.startPrefixMapping(prefix, ns.getURI());
|
|
938 }
|
|
939 catch (SAXException se) {
|
|
940 throw new JDOMException(
|
|
941 "Exception in startPrefixMapping", se);
|
|
942 }
|
|
943 }
|
|
944 }
|
|
945
|
|
946 // Fire additional namespace declarations
|
|
947 List additionalNamespaces = element.getAdditionalNamespaces();
|
|
948 if (additionalNamespaces != null) {
|
|
949 Iterator itr = additionalNamespaces.iterator();
|
|
950 while (itr.hasNext()) {
|
|
951 ns = (Namespace)itr.next();
|
|
952 String prefix = ns.getPrefix();
|
|
953 String uri = namespaces.getURI(prefix);
|
|
954 if (!ns.getURI().equals(uri)) {
|
|
955 namespaces.push(ns);
|
|
956 nsAtts = this.addNsAttribute(nsAtts, ns);
|
|
957 try {
|
|
958 contentHandler.startPrefixMapping(prefix, ns.getURI());
|
|
959 }
|
|
960 catch (SAXException se) {
|
|
961 throw new JDOMException(
|
|
962 "Exception in startPrefixMapping", se);
|
|
963 }
|
|
964 }
|
|
965 }
|
|
966 }
|
|
967 return nsAtts;
|
|
968 }
|
|
969
|
|
970 /**
|
|
971 * <p>
|
|
972 * This will invoke the <code>endPrefixMapping</code> callback in the
|
|
973 * <code>ContentHandler</code> when a namespace is goes out of scope
|
|
974 * in the <code>Document</code>.
|
|
975 * </p>
|
|
976 *
|
|
977 * @param namespaces <code>List</code> stack of Namespaces in scope.
|
|
978 * @param previouslyDeclaredNamespaces number of previously declared
|
|
979 * namespaces
|
|
980 */
|
|
981 private void endPrefixMapping(NamespaceStack namespaces,
|
|
982 int previouslyDeclaredNamespaces)
|
|
983 throws JDOMException {
|
|
984 while (namespaces.size() > previouslyDeclaredNamespaces) {
|
|
985 String prefix = namespaces.pop();
|
|
986 try {
|
|
987 contentHandler.endPrefixMapping(prefix);
|
|
988 }
|
|
989 catch (SAXException se) {
|
|
990 throw new JDOMException("Exception in endPrefixMapping", se);
|
|
991 }
|
|
992 }
|
|
993 }
|
|
994
|
|
995 /**
|
|
996 * <p>
|
|
997 * This will invoke the <code>startElement</code> callback
|
|
998 * in the <code>ContentHandler</code>.
|
|
999 * </p>
|
|
1000 *
|
|
1001 * @param element <code>Element</code> used in callbacks.
|
|
1002 * @param nsAtts <code>List</code> of namespaces to declare with
|
|
1003 * the element or <code>null</code>.
|
|
1004 */
|
|
1005 private void startElement(Element element, Attributes nsAtts)
|
|
1006 throws JDOMException {
|
|
1007 String namespaceURI = element.getNamespaceURI();
|
|
1008 String localName = element.getName();
|
|
1009 String rawName = element.getQualifiedName();
|
|
1010
|
|
1011 // Allocate attribute list.
|
|
1012 AttributesImpl atts = (nsAtts != null)?
|
|
1013 new AttributesImpl(nsAtts): new AttributesImpl();
|
|
1014
|
|
1015 List attributes = element.getAttributes();
|
|
1016 Iterator i = attributes.iterator();
|
|
1017 while (i.hasNext()) {
|
|
1018 Attribute a = (Attribute) i.next();
|
|
1019 atts.addAttribute(a.getNamespaceURI(),
|
|
1020 a.getName(),
|
|
1021 a.getQualifiedName(),
|
|
1022 getAttributeTypeName(a.getAttributeType()),
|
|
1023 a.getValue());
|
|
1024 }
|
|
1025
|
|
1026 try {
|
|
1027 contentHandler.startElement(namespaceURI, localName, rawName, atts);
|
|
1028 }
|
|
1029 catch (SAXException se) {
|
|
1030 throw new JDOMException("Exception in startElement", se);
|
|
1031 }
|
|
1032 }
|
|
1033
|
|
1034 /**
|
|
1035 * <p>
|
|
1036 * This will invoke the <code>endElement</code> callback
|
|
1037 * in the <code>ContentHandler</code>.
|
|
1038 * </p>
|
|
1039 *
|
|
1040 * @param element <code>Element</code> used in callbacks.
|
|
1041 */
|
|
1042 private void endElement(Element element) throws JDOMException {
|
|
1043 String namespaceURI = element.getNamespaceURI();
|
|
1044 String localName = element.getName();
|
|
1045 String rawName = element.getQualifiedName();
|
|
1046
|
|
1047 try {
|
|
1048 contentHandler.endElement(namespaceURI, localName, rawName);
|
|
1049 }
|
|
1050 catch (SAXException se) {
|
|
1051 throw new JDOMException("Exception in endElement", se);
|
|
1052 }
|
|
1053 }
|
|
1054
|
|
1055 /**
|
|
1056 * <p>
|
|
1057 * This will invoke the callbacks for the content of an element.
|
|
1058 * </p>
|
|
1059 *
|
|
1060 * @param content element content as a <code>List</code> of nodes.
|
|
1061 * @param namespaces <code>List</code> stack of Namespaces in scope.
|
|
1062 */
|
|
1063 private void elementContent(List content, NamespaceStack namespaces)
|
|
1064 throws JDOMException {
|
|
1065 for (Iterator i=content.iterator(); i.hasNext(); ) {
|
|
1066 Object obj = i.next();
|
|
1067
|
|
1068 if (obj instanceof Content) {
|
|
1069 this.elementContent((Content)obj, namespaces);
|
|
1070 }
|
|
1071 else {
|
|
1072 // Not a valid element child. This could happen with
|
|
1073 // application-provided lists which may contain non
|
|
1074 // JDOM objects.
|
|
1075 handleError(new JDOMException(
|
|
1076 "Invalid element content: " + obj));
|
|
1077 }
|
|
1078 }
|
|
1079 }
|
|
1080
|
|
1081 /**
|
|
1082 * <p>
|
|
1083 * This will invoke the callbacks for the content of an element.
|
|
1084 * </p>
|
|
1085 *
|
|
1086 * @param node a <code>Content</code> node.
|
|
1087 * @param namespaces <code>List</code> stack of Namespaces in scope.
|
|
1088 */
|
|
1089 private void elementContent(Content node, NamespaceStack namespaces)
|
|
1090 throws JDOMException {
|
|
1091 // update locator
|
|
1092 if (locator != null) {
|
|
1093 locator.setNode(node);
|
|
1094 }
|
|
1095
|
|
1096 if (node instanceof Element) {
|
|
1097 element((Element) node, namespaces);
|
|
1098 }
|
|
1099 else if (node instanceof CDATA) {
|
|
1100 cdata(((CDATA) node).getText());
|
|
1101 }
|
|
1102 else if (node instanceof Text) {
|
|
1103 // contentHandler.characters()
|
|
1104 characters(((Text) node).getText());
|
|
1105 }
|
|
1106 else if (node instanceof ProcessingInstruction) {
|
|
1107 // contentHandler.processingInstruction()
|
|
1108 processingInstruction((ProcessingInstruction) node);
|
|
1109 }
|
|
1110 else if (node instanceof Comment) {
|
|
1111 // lexicalHandler.comment()
|
|
1112 comment(((Comment) node).getText());
|
|
1113 }
|
|
1114 else if (node instanceof EntityRef) {
|
|
1115 // contentHandler.skippedEntity()
|
|
1116 entityRef((EntityRef) node);
|
|
1117 }
|
|
1118 else {
|
|
1119 // Not a valid element child. This could happen with
|
|
1120 // application-provided lists which may contain non
|
|
1121 // JDOM objects.
|
|
1122 handleError(new JDOMException("Invalid element content: " + node));
|
|
1123 }
|
|
1124 }
|
|
1125
|
|
1126 /**
|
|
1127 * <p>
|
|
1128 * This will be called for each chunk of CDATA section encountered.
|
|
1129 * </p>
|
|
1130 *
|
|
1131 * @param cdataText all text in the CDATA section, including whitespace.
|
|
1132 */
|
|
1133 private void cdata(String cdataText) throws JDOMException {
|
|
1134 try {
|
|
1135 if (lexicalHandler != null) {
|
|
1136 lexicalHandler.startCDATA();
|
|
1137 characters(cdataText);
|
|
1138 lexicalHandler.endCDATA();
|
|
1139 }
|
|
1140 else {
|
|
1141 characters(cdataText);
|
|
1142 }
|
|
1143 }
|
|
1144 catch (SAXException se) {
|
|
1145 throw new JDOMException("Exception in CDATA", se);
|
|
1146 }
|
|
1147 }
|
|
1148
|
|
1149 /**
|
|
1150 * <p>
|
|
1151 * This will be called for each chunk of character data encountered.
|
|
1152 * </p>
|
|
1153 *
|
|
1154 * @param elementText all text in an element, including whitespace.
|
|
1155 */
|
|
1156 private void characters(String elementText) throws JDOMException {
|
|
1157 char[] c = elementText.toCharArray();
|
|
1158 try {
|
|
1159 contentHandler.characters(c, 0, c.length);
|
|
1160 }
|
|
1161 catch (SAXException se) {
|
|
1162 throw new JDOMException("Exception in characters", se);
|
|
1163 }
|
|
1164 }
|
|
1165
|
|
1166 /**
|
|
1167 * <p>
|
|
1168 * This will be called for each chunk of comment data encontered.
|
|
1169 * </p>
|
|
1170 *
|
|
1171 * @param commentText all text in a comment, including whitespace.
|
|
1172 */
|
|
1173 private void comment(String commentText) throws JDOMException {
|
|
1174 if (lexicalHandler != null) {
|
|
1175 char[] c = commentText.toCharArray();
|
|
1176 try {
|
|
1177 lexicalHandler.comment(c, 0, c.length);
|
|
1178 } catch (SAXException se) {
|
|
1179 throw new JDOMException("Exception in comment", se);
|
|
1180 }
|
|
1181 }
|
|
1182 }
|
|
1183
|
|
1184 /**
|
|
1185 * <p>
|
|
1186 * This will invoke the <code>ContentHandler.skippedEntity</code>
|
|
1187 * callback when an entity reference is encountered.
|
|
1188 * </p>
|
|
1189 *
|
|
1190 * @param entity <code>EntityRef</code>.
|
|
1191 */
|
|
1192 private void entityRef(EntityRef entity) throws JDOMException {
|
|
1193 if (entity != null) {
|
|
1194 try {
|
|
1195 // No need to worry about appending a '%' character as
|
|
1196 // we do not support parameter entities
|
|
1197 contentHandler.skippedEntity(entity.getName());
|
|
1198 }
|
|
1199 catch (SAXException se) {
|
|
1200 throw new JDOMException("Exception in entityRef", se);
|
|
1201 }
|
|
1202 }
|
|
1203 }
|
|
1204
|
|
1205
|
|
1206 /**
|
|
1207 * <p>
|
|
1208 * Appends a namespace declaration in the form of a xmlns attribute to
|
|
1209 * an attribute list, crerating this latter if needed.
|
|
1210 * </p>
|
|
1211 *
|
|
1212 * @param atts <code>AttributeImpl</code> where to add the attribute.
|
|
1213 * @param ns <code>Namespace</code> the namespace to declare.
|
|
1214 *
|
|
1215 * @return <code>AttributeImpl</code> the updated attribute list.
|
|
1216 */
|
|
1217 private AttributesImpl addNsAttribute(AttributesImpl atts, Namespace ns) {
|
|
1218 if (this.declareNamespaces) {
|
|
1219 if (atts == null) {
|
|
1220 atts = new AttributesImpl();
|
|
1221 }
|
|
1222
|
|
1223 String prefix = ns.getPrefix();
|
|
1224 if (prefix.equals("")) {
|
|
1225 atts.addAttribute("", // namespace
|
|
1226 "", // local name
|
|
1227 "xmlns", // qualified name
|
|
1228 "CDATA", // type
|
|
1229 ns.getURI()); // value
|
|
1230 }
|
|
1231 else {
|
|
1232 atts.addAttribute("", // namespace
|
|
1233 "", // local name
|
|
1234 "xmlns:" + ns.getPrefix(), // qualified name
|
|
1235 "CDATA", // type
|
|
1236 ns.getURI()); // value
|
|
1237 }
|
|
1238 }
|
|
1239 return atts;
|
|
1240 }
|
|
1241
|
|
1242 /**
|
|
1243 * <p>
|
|
1244 * Returns the SAX 2.0 attribute type string from the type of
|
|
1245 * a JDOM Attribute.
|
|
1246 * </p>
|
|
1247 *
|
|
1248 * @param type <code>int</code> the type of the JDOM attribute.
|
|
1249 *
|
|
1250 * @return <code>String</code> the SAX 2.0 attribute type string.
|
|
1251 *
|
|
1252 * @see org.jdom.Attribute#getAttributeType
|
|
1253 * @see org.xml.sax.Attributes#getType
|
|
1254 */
|
|
1255 private static String getAttributeTypeName(int type) {
|
|
1256 if ((type < 0) || (type >= attrTypeToNameMap.length)) {
|
|
1257 type = Attribute.UNDECLARED_TYPE;
|
|
1258 }
|
|
1259 return attrTypeToNameMap[type];
|
|
1260 }
|
|
1261
|
|
1262 /**
|
|
1263 * <p>
|
|
1264 * Notifies the registered {@link ErrorHandler SAX error handler}
|
|
1265 * (if any) of an input processing error. The error handler can
|
|
1266 * choose to absorb the error and let the processing continue.
|
|
1267 * </p>
|
|
1268 *
|
|
1269 * @param exception <code>JDOMException</code> containing the
|
|
1270 * error information; will be wrapped in a
|
|
1271 * {@link SAXParseException} when reported to
|
|
1272 * the SAX error handler.
|
|
1273 *
|
|
1274 * @throws JDOMException if no error handler has been registered
|
|
1275 * or if the error handler fired a
|
|
1276 * {@link SAXException}.
|
|
1277 */
|
|
1278 private void handleError(JDOMException exception) throws JDOMException {
|
|
1279 if (errorHandler != null) {
|
|
1280 try {
|
|
1281 errorHandler.error(new SAXParseException(
|
|
1282 exception.getMessage(), null, exception));
|
|
1283 }
|
|
1284 catch (SAXException se) {
|
|
1285 if (se.getException() instanceof JDOMException) {
|
|
1286 throw (JDOMException)(se.getException());
|
|
1287 }
|
|
1288 else {
|
|
1289 throw new JDOMException(se.getMessage(), se);
|
|
1290 }
|
|
1291 }
|
|
1292 }
|
|
1293 else {
|
|
1294 throw exception;
|
|
1295 }
|
|
1296 }
|
|
1297
|
|
1298 /**
|
|
1299 * <p>
|
|
1300 * Creates a SAX XMLReader.
|
|
1301 * </p>
|
|
1302 *
|
|
1303 * @return <code>XMLReader</code> a SAX2 parser.
|
|
1304 *
|
|
1305 * @throws Exception if no parser can be created.
|
|
1306 */
|
|
1307 protected XMLReader createParser() throws Exception {
|
|
1308 XMLReader parser = null;
|
|
1309
|
|
1310 // Try using JAXP...
|
|
1311 // Note we need JAXP 1.1, and if JAXP 1.0 is all that's
|
|
1312 // available then the getXMLReader call fails and we skip
|
|
1313 // to the hard coded default parser
|
|
1314 try {
|
|
1315 Class factoryClass =
|
|
1316 Class.forName("javax.xml.parsers.SAXParserFactory");
|
|
1317
|
|
1318 // factory = SAXParserFactory.newInstance();
|
|
1319 Method newParserInstance =
|
|
1320 factoryClass.getMethod("newInstance", null);
|
|
1321 Object factory = newParserInstance.invoke(null, null);
|
|
1322
|
|
1323 // jaxpParser = factory.newSAXParser();
|
|
1324 Method newSAXParser = factoryClass.getMethod("newSAXParser", null);
|
|
1325 Object jaxpParser = newSAXParser.invoke(factory, null);
|
|
1326
|
|
1327 // parser = jaxpParser.getXMLReader();
|
|
1328 Class parserClass = jaxpParser.getClass();
|
|
1329 Method getXMLReader =
|
|
1330 parserClass.getMethod("getXMLReader", null);
|
|
1331 parser = (XMLReader)getXMLReader.invoke(jaxpParser, null);
|
|
1332 } catch (ClassNotFoundException e) {
|
|
1333 //e.printStackTrace();
|
|
1334 } catch (InvocationTargetException e) {
|
|
1335 //e.printStackTrace();
|
|
1336 } catch (NoSuchMethodException e) {
|
|
1337 //e.printStackTrace();
|
|
1338 } catch (IllegalAccessException e) {
|
|
1339 //e.printStackTrace();
|
|
1340 }
|
|
1341
|
|
1342 // Check to see if we got a parser yet, if not, try to use a
|
|
1343 // hard coded default
|
|
1344 if (parser == null) {
|
|
1345 parser = XMLReaderFactory.createXMLReader(
|
|
1346 "org.apache.xerces.parsers.SAXParser");
|
|
1347 }
|
|
1348 return parser;
|
|
1349 }
|
|
1350
|
|
1351 /**
|
|
1352 * <p>
|
|
1353 * This will create a SAX XMLReader capable of parsing a DTD and
|
|
1354 * configure it so that the DTD parsing events are routed to the
|
|
1355 * handlers registered onto this SAXOutputter.
|
|
1356 * </p>
|
|
1357 *
|
|
1358 * @return <code>XMLReader</code> a SAX2 parser.
|
|
1359 *
|
|
1360 * @throws JDOMException if no parser can be created.
|
|
1361 */
|
|
1362 private XMLReader createDTDParser() throws JDOMException {
|
|
1363 XMLReader parser = null;
|
|
1364
|
|
1365 // Get a parser instance
|
|
1366 try
|
|
1367 {
|
|
1368 parser = createParser();
|
|
1369 }
|
|
1370 catch (Exception ex1) {
|
|
1371 throw new JDOMException("Error in SAX parser allocation", ex1);
|
|
1372 }
|
|
1373
|
|
1374 // Register handlers
|
|
1375 if (this.getDTDHandler() != null) {
|
|
1376 parser.setDTDHandler(this.getDTDHandler());
|
|
1377 }
|
|
1378 if (this.getEntityResolver() != null) {
|
|
1379 parser.setEntityResolver(this.getEntityResolver());
|
|
1380 }
|
|
1381 if (this.getLexicalHandler() != null) {
|
|
1382 try {
|
|
1383 parser.setProperty(LEXICAL_HANDLER_SAX_PROPERTY,
|
|
1384 this.getLexicalHandler());
|
|
1385 }
|
|
1386 catch (SAXException ex1) {
|
|
1387 try {
|
|
1388 parser.setProperty(LEXICAL_HANDLER_ALT_PROPERTY,
|
|
1389 this.getLexicalHandler());
|
|
1390 } catch (SAXException ex2) {
|
|
1391 // Forget it!
|
|
1392 }
|
|
1393 }
|
|
1394 }
|
|
1395 if (this.getDeclHandler() != null) {
|
|
1396 try {
|
|
1397 parser.setProperty(DECL_HANDLER_SAX_PROPERTY,
|
|
1398 this.getDeclHandler());
|
|
1399 }
|
|
1400 catch (SAXException ex1) {
|
|
1401 try {
|
|
1402 parser.setProperty(DECL_HANDLER_ALT_PROPERTY,
|
|
1403 this.getDeclHandler());
|
|
1404 } catch (SAXException ex2) {
|
|
1405 // Forget it!
|
|
1406 }
|
|
1407 }
|
|
1408 }
|
|
1409
|
|
1410 // Absorb errors as much as possible, per Laurent
|
|
1411 parser.setErrorHandler(new DefaultHandler());
|
|
1412
|
|
1413 return parser;
|
|
1414 }
|
|
1415
|
|
1416 /**
|
|
1417 * Returns a JDOMLocator object referencing the node currently
|
|
1418 * being processed by this outputter. The returned object is a
|
|
1419 * snapshot of the location information and can thus safely be
|
|
1420 * memorized for later use.
|
|
1421 * <p>
|
|
1422 * This method allows direct access to the location information
|
|
1423 * maintained by SAXOutputter without requiring to implement
|
|
1424 * <code>XMLFilter</code>. (In SAX, locators are only available
|
|
1425 * though the <code>ContentHandler</code> interface).</p>
|
|
1426 * <p>
|
|
1427 * Note that location information is only available while
|
|
1428 * SAXOutputter is outputting nodes. Hence this method should
|
|
1429 * only be used by objects taking part in the output processing
|
|
1430 * such as <code>ErrorHandler</code>s.
|
|
1431 *
|
|
1432 * @return a JDOMLocator object referencing the node currently
|
|
1433 * being processed or <code>null</code> if no output
|
|
1434 * operation is being performed.
|
|
1435 */
|
|
1436 public JDOMLocator getLocator() {
|
|
1437 return (locator != null)? new JDOMLocator(locator): null;
|
|
1438 }
|
|
1439 }
|