Clover coverage report - dom4j - 1.6.1
Coverage timestamp: ma mei 16 2005 14:23:01 GMT+01:00

file stats: | LOC: | 945 |  | Methods: | 48
| NCLOC: | 436 |  | Classes: | 1

Source file | Conditionals | Statements | Methods | TOTAL

SAXWriter.java

65,5%

62,2%

66,7%

63,6%

1 |  | /*
2 |  | * Copyright 2001-2005 (C) MetaStuff, Ltd. All Rights Reserved.
3 |  | *
4 |  | * This software is open source.
5 |  | * See the bottom of this file for the licence.
6 |  | */
7 |  |
8 |  | package org.dom4j.io;
9 |  |
10 |  | import java.io.IOException;
11 |  | import java.util.HashMap;
12 |  | import java.util.Iterator;
13 |  | import java.util.List;
14 |  | import java.util.Map;
15 |  |
16 |  | import org.dom4j.Attribute;
17 |  | import org.dom4j.Branch;
18 |  | import org.dom4j.CDATA;
19 |  | import org.dom4j.CharacterData;
20 |  | import org.dom4j.Comment;
21 |  | import org.dom4j.Document;
22 |  | import org.dom4j.DocumentType;
23 |  | import org.dom4j.Element;
24 |  | import org.dom4j.Entity;
25 |  | import org.dom4j.Namespace;
26 |  | import org.dom4j.Node;
27 |  | import org.dom4j.ProcessingInstruction;
28 |  | import org.dom4j.Text;
29 |  | import org.dom4j.tree.NamespaceStack;
30 |  |
31 |  | import org.xml.sax.Attributes;
32 |  | import org.xml.sax.ContentHandler;
33 |  | import org.xml.sax.DTDHandler;
34 |  | import org.xml.sax.EntityResolver;
35 |  | import org.xml.sax.ErrorHandler;
36 |  | import org.xml.sax.InputSource;
37 |  | import org.xml.sax.SAXException;
38 |  | import org.xml.sax.SAXNotRecognizedException;
39 |  | import org.xml.sax.SAXNotSupportedException;
40 |  | import org.xml.sax.XMLReader;
41 |  | import org.xml.sax.ext.LexicalHandler;
42 |  | import org.xml.sax.helpers.AttributesImpl;
43 |  | import org.xml.sax.helpers.LocatorImpl;
44 |  |
45 |  | /**
46 |  | * <p>
47 |  | * <code>SAXWriter</code> writes a DOM4J tree to a SAX ContentHandler.
48 |  | * </p>
49 |  | *
50 |  | * @author <a href="mailto:james.strachan@metastuff.com">James Strachan </a>
51 |  | * @version $Revision: 1.24 $
52 |  | */
53 |  | public class SAXWriter implements XMLReader {
54 |  | protected static final String[] LEXICAL_HANDLER_NAMES = {
55 |  | "http://xml.org/sax/properties/lexical-handler",
56 |  | "http://xml.org/sax/handlers/LexicalHandler" };
57 |  |
58 |  | protected static final String FEATURE_NAMESPACE_PREFIXES
59 |  | = "http://xml.org/sax/features/namespace-prefixes";
60 |  |
61 |  | protected static final String FEATURE_NAMESPACES
62 |  | = "http://xml.org/sax/features/namespaces";
63 |  |
64 |  | /** <code>ContentHandler</code> to which SAX events are raised */
65 |  | private ContentHandler contentHandler;
66 |  |
67 |  | /** <code>DTDHandler</code> fired when a document has a DTD */
68 |  | private DTDHandler dtdHandler;
69 |  |
70 |  | /** <code>EntityResolver</code> fired when a document has a DTD */
71 |  | private EntityResolver entityResolver;
72 |  |
73 |  | private ErrorHandler errorHandler;
74 |  |
75 |  | /** <code>LexicalHandler</code> fired on Entity and CDATA sections */
76 |  | private LexicalHandler lexicalHandler;
77 |  |
78 |  | /** <code>AttributesImpl</code> used when generating the Attributes */
79 |  | private AttributesImpl attributes = new AttributesImpl();
80 |  |
81 |  | /** Stores the features */
82 |  | private Map features = new HashMap();
83 |  |
84 |  | /** Stores the properties */
85 |  | private Map properties = new HashMap();
86 |  |
87 |  | /** Whether namespace declarations are exported as attributes or not */
88 |  | private boolean declareNamespaceAttributes;
89 |  |
90 | 20 | public SAXWriter() {
91 | 20 | properties.put(FEATURE_NAMESPACE_PREFIXES, Boolean.FALSE);
92 | 20 | properties.put(FEATURE_NAMESPACE_PREFIXES, Boolean.TRUE);
93 |  | }
94 |  |
95 | 0 | public SAXWriter(ContentHandler contentHandler) {
96 | 0 | this();
97 | 0 | this.contentHandler = contentHandler;
98 |  | }
99 |  |
100 | 0 | public SAXWriter(ContentHandler contentHandler,
101 |  | LexicalHandler lexicalHandler) {
102 | 0 | this();
103 | 0 | this.contentHandler = contentHandler;
104 | 0 | this.lexicalHandler = lexicalHandler;
105 |  | }
106 |  |
107 | 12 | public SAXWriter(ContentHandler contentHandler,
108 |  | LexicalHandler lexicalHandler, EntityResolver entityResolver) {
109 | 12 | this();
110 | 12 | this.contentHandler = contentHandler;
111 | 12 | this.lexicalHandler = lexicalHandler;
112 | 12 | this.entityResolver = entityResolver;
113 |  | }
114 |  |
115 |  | /**
116 |  | * A polymorphic method to write any Node to this SAX stream
117 |  | *
118 |  | * @param node
119 |  | * DOCUMENT ME!
120 |  | *
121 |  | * @throws SAXException
122 |  | * DOCUMENT ME!
123 |  | */
124 | 39 | public void write(Node node) throws SAXException {
125 | 39 | int nodeType = node.getNodeType();
126 |  |
127 | 39 | switch (nodeType) {
128 | 0 | case Node.ELEMENT_NODE:
129 | 0 | write((Element) node);
130 |  |
131 | 0 | break;
132 |  |
133 | 0 | case Node.ATTRIBUTE_NODE:
134 | 0 | write((Attribute) node);
135 |  |
136 | 0 | break;
137 |  |
138 | 0 | case Node.TEXT_NODE:
139 | 0 | write(node.getText());
140 |  |
141 | 0 | break;
142 |  |
143 | 0 | case Node.CDATA_SECTION_NODE:
144 | 0 | write((CDATA) node);
145 |  |
146 | 0 | break;
147 |  |
148 | 0 | case Node.ENTITY_REFERENCE_NODE:
149 | 0 | write((Entity) node);
150 |  |
151 | 0 | break;
152 |  |
153 | 0 | case Node.PROCESSING_INSTRUCTION_NODE:
154 | 0 | write((ProcessingInstruction) node);
155 |  |
156 | 0 | break;
157 |  |
158 | 0 | case Node.COMMENT_NODE:
159 | 0 | write((Comment) node);
160 |  |
161 | 0 | break;
162 |  |
163 | 0 | case Node.DOCUMENT_NODE:
164 | 0 | write((Document) node);
165 |  |
166 | 0 | break;
167 |  |
168 | 0 | case Node.DOCUMENT_TYPE_NODE:
169 | 0 | write((DocumentType) node);
170 |  |
171 | 0 | break;
172 |  |
173 | 39 | case Node.NAMESPACE_NODE:
174 |  |
175 |  | // Will be output with attributes
176 |  | // write((Namespace) node);
177 | 39 | break;
178 |  |
179 | 0 | default:
180 | 0 | throw new SAXException("Invalid node type: " + node);
181 |  | }
182 |  | }
183 |  |
184 |  | /**
185 |  | * Generates SAX events for the given Document and all its content
186 |  | *
187 |  | * @param document
188 |  | * is the Document to parse
189 |  | *
190 |  | * @throws SAXException
191 |  | * if there is a SAX error processing the events
192 |  | */
193 | 20 | public void write(Document document) throws SAXException {
194 | 20 | if (document != null) {
195 | 20 | checkForNullHandlers();
196 |  |
197 | 20 | documentLocator(document);
198 | 20 | startDocument();
199 | 20 | entityResolver(document);
200 | 20 | dtdHandler(document);
201 |  |
202 | 20 | writeContent(document, new NamespaceStack());
203 | 20 | endDocument();
204 |  | }
205 |  | }
206 |  |
207 |  | /**
208 |  | * Generates SAX events for the given Element and all its content
209 |  | *
210 |  | * @param element
211 |  | * is the Element to parse
212 |  | *
213 |  | * @throws SAXException
214 |  | * if there is a SAX error processing the events
215 |  | */
216 | 0 | public void write(Element element) throws SAXException {
217 | 0 | write(element, new NamespaceStack());
218 |  | }
219 |  |
220 |  | /**
221 |  | * <p>
222 |  | * Writes the opening tag of an {@link Element}, including its {@link
223 |  | * Attribute}s but without its content.
224 |  | * </p>
225 |  | *
226 |  | * @param element
227 |  | * <code>Element</code> to output.
228 |  | *
229 |  | * @throws SAXException
230 |  | * DOCUMENT ME!
231 |  | */
232 | 0 | public void writeOpen(Element element) throws SAXException {
233 | 0 | startElement(element, null);
234 |  | }
235 |  |
236 |  | /**
237 |  | * <p>
238 |  | * Writes the closing tag of an {@link Element}
239 |  | * </p>
240 |  | *
241 |  | * @param element
242 |  | * <code>Element</code> to output.
243 |  | *
244 |  | * @throws SAXException
245 |  | * DOCUMENT ME!
246 |  | */
247 | 0 | public void writeClose(Element element) throws SAXException {
248 | 0 | endElement(element);
249 |  | }
250 |  |
251 |  | /**
252 |  | * Generates SAX events for the given text
253 |  | *
254 |  | * @param text
255 |  | * is the text to send to the SAX ContentHandler
256 |  | *
257 |  | * @throws SAXException
258 |  | * if there is a SAX error processing the events
259 |  | */
260 | 12162 | public void write(String text) throws SAXException {
261 | 12162 | if (text != null) {
262 | 12162 | char[] chars = text.toCharArray();
263 | 12162 | contentHandler.characters(chars, 0, chars.length);
264 |  | }
265 |  | }
266 |  |
267 |  | /**
268 |  | * Generates SAX events for the given CDATA
269 |  | *
270 |  | * @param cdata
271 |  | * is the CDATA to parse
272 |  | *
273 |  | * @throws SAXException
274 |  | * if there is a SAX error processing the events
275 |  | */
276 | 30 | public void write(CDATA cdata) throws SAXException {
277 | 30 | String text = cdata.getText();
278 |  |
279 | 30 | if (lexicalHandler != null) {
280 | 30 | lexicalHandler.startCDATA();
281 | 30 | write(text);
282 | 30 | lexicalHandler.endCDATA();
283 |  | } else {
284 | 0 | write(text);
285 |  | }
286 |  | }
287 |  |
288 |  | /**
289 |  | * Generates SAX events for the given Comment
290 |  | *
291 |  | * @param comment
292 |  | * is the Comment to parse
293 |  | *
294 |  | * @throws SAXException
295 |  | * if there is a SAX error processing the events
296 |  | */
297 | 71 | public void write(Comment comment) throws SAXException {
298 | 71 | if (lexicalHandler != null) {
299 | 71 | String text = comment.getText();
300 | 71 | char[] chars = text.toCharArray();
301 | 71 | lexicalHandler.comment(chars, 0, chars.length);
302 |  | }
303 |  | }
304 |  |
305 |  | /**
306 |  | * Generates SAX events for the given Entity
307 |  | *
308 |  | * @param entity
309 |  | * is the Entity to parse
310 |  | *
311 |  | * @throws SAXException
312 |  | * if there is a SAX error processing the events
313 |  | */
314 | 0 | public void write(Entity entity) throws SAXException {
315 | 0 | String text = entity.getText();
316 |  |
317 | 0 | if (lexicalHandler != null) {
318 | 0 | String name = entity.getName();
319 | 0 | lexicalHandler.startEntity(name);
320 | 0 | write(text);
321 | 0 | lexicalHandler.endEntity(name);
322 |  | } else {
323 | 0 | write(text);
324 |  | }
325 |  | }
326 |  |
327 |  | /**
328 |  | * Generates SAX events for the given ProcessingInstruction
329 |  | *
330 |  | * @param pi
331 |  | * is the ProcessingInstruction to parse
332 |  | *
333 |  | * @throws SAXException
334 |  | * if there is a SAX error processing the events
335 |  | */
336 | 2 | public void write(ProcessingInstruction pi) throws SAXException {
337 | 2 | String target = pi.getTarget();
338 | 2 | String text = pi.getText();
339 | 2 | contentHandler.processingInstruction(target, text);
340 |  | }
341 |  |
342 |  | /**
343 |  | * Should namespace declarations be converted to "xmlns" attributes. This
344 |  | * property defaults to <code>false</code> as per the SAX specification.
345 |  | * This property is set via the SAX feature
346 |  | * "http://xml.org/sax/features/namespace-prefixes"
347 |  | *
348 |  | * @return DOCUMENT ME!
349 |  | */
350 | 0 | public boolean isDeclareNamespaceAttributes() {
351 | 0 | return declareNamespaceAttributes;
352 |  | }
353 |  |
354 |  | /**
355 |  | * Sets whether namespace declarations should be exported as "xmlns"
356 |  | * attributes or not. This property is set from the SAX feature
357 |  | * "http://xml.org/sax/features/namespace-prefixes"
358 |  | *
359 |  | * @param declareNamespaceAttrs
360 |  | * DOCUMENT ME!
361 |  | */
362 | 8 | public void setDeclareNamespaceAttributes(boolean declareNamespaceAttrs) {
363 | 8 | this.declareNamespaceAttributes = declareNamespaceAttrs;
364 |  | }
365 |  |
366 |  | // XMLReader methods
367 |  | // -------------------------------------------------------------------------
368 |  |
369 |  | /**
370 |  | * DOCUMENT ME!
371 |  | *
372 |  | * @return the <code>ContentHandler</code> called when SAX events are
373 |  | * raised
374 |  | */
375 | 0 | public ContentHandler getContentHandler() {
376 | 0 | return contentHandler;
377 |  | }
378 |  |
379 |  | /**
380 |  | * Sets the <code>ContentHandler</code> called when SAX events are raised
381 |  | *
382 |  | * @param contentHandler
383 |  | * is the <code>ContentHandler</code> called when SAX events
384 |  | * are raised
385 |  | */
386 | 8 | public void setContentHandler(ContentHandler contentHandler) {
387 | 8 | this.contentHandler = contentHandler;
388 |  | }
389 |  |
390 |  | /**
391 |  | * DOCUMENT ME!
392 |  | *
393 |  | * @return the <code>DTDHandler</code>
394 |  | */
395 | 0 | public DTDHandler getDTDHandler() {
396 | 0 | return dtdHandler;
397 |  | }
398 |  |
399 |  | /**
400 |  | * Sets the <code>DTDHandler</code>.
401 |  | *
402 |  | * @param handler
403 |  | * DOCUMENT ME!
404 |  | */
405 | 8 | public void setDTDHandler(DTDHandler handler) {
406 | 8 | this.dtdHandler = handler;
407 |  | }
408 |  |
409 |  | /**
410 |  | * DOCUMENT ME!
411 |  | *
412 |  | * @return the <code>ErrorHandler</code>
413 |  | */
414 | 1 | public ErrorHandler getErrorHandler() {
415 | 1 | return errorHandler;
416 |  | }
417 |  |
418 |  | /**
419 |  | * Sets the <code>ErrorHandler</code>.
420 |  | *
421 |  | * @param errorHandler
422 |  | * DOCUMENT ME!
423 |  | */
424 | 1 | public void setErrorHandler(ErrorHandler errorHandler) {
425 | 1 | this.errorHandler = errorHandler;
426 |  | }
427 |  |
428 |  | /**
429 |  | * DOCUMENT ME!
430 |  | *
431 |  | * @return the <code>EntityResolver</code> used when a Document contains a
432 |  | * DTD
433 |  | */
434 | 0 | public EntityResolver getEntityResolver() {
435 | 0 | return entityResolver;
436 |  | }
437 |  |
438 |  | /**
439 |  | * Sets the <code>EntityResolver</code>.
440 |  | *
441 |  | * @param entityResolver
442 |  | * is the <code>EntityResolver</code>
443 |  | */
444 | 0 | public void setEntityResolver(EntityResolver entityResolver) {
445 | 0 | this.entityResolver = entityResolver;
446 |  | }
447 |  |
448 |  | /**
449 |  | * DOCUMENT ME!
450 |  | *
451 |  | * @return the <code>LexicalHandler</code> used when a Document contains a
452 |  | * DTD
453 |  | */
454 | 0 | public LexicalHandler getLexicalHandler() {
455 | 0 | return lexicalHandler;
456 |  | }
457 |  |
458 |  | /**
459 |  | * Sets the <code>LexicalHandler</code>.
460 |  | *
461 |  | * @param lexicalHandler
462 |  | * is the <code>LexicalHandler</code>
463 |  | */
464 | 15 | public void setLexicalHandler(LexicalHandler lexicalHandler) {
465 | 15 | this.lexicalHandler = lexicalHandler;
466 |  | }
467 |  |
468 |  | /**
469 |  | * Sets the <code>XMLReader</code> used to write SAX events to
470 |  | *
471 |  | * @param xmlReader
472 |  | * is the <code>XMLReader</code>
473 |  | */
474 | 0 | public void setXMLReader(XMLReader xmlReader) {
475 | 0 | setContentHandler(xmlReader.getContentHandler());
476 | 0 | setDTDHandler(xmlReader.getDTDHandler());
477 | 0 | setEntityResolver(xmlReader.getEntityResolver());
478 | 0 | setErrorHandler(xmlReader.getErrorHandler());
479 |  | }
480 |  |
481 |  | /**
482 |  | * Looks up the value of a feature.
483 |  | *
484 |  | * @param name
485 |  | * DOCUMENT ME!
486 |  | *
487 |  | * @return DOCUMENT ME!
488 |  | *
489 |  | * @throws SAXNotRecognizedException
490 |  | * DOCUMENT ME!
491 |  | * @throws SAXNotSupportedException
492 |  | * DOCUMENT ME!
493 |  | */
494 | 0 | public boolean getFeature(String name) throws SAXNotRecognizedException,
495 |  | SAXNotSupportedException {
496 | 0 | Boolean answer = (Boolean) features.get(name);
497 |  |
498 | 0 | return (answer != null) && answer.booleanValue();
499 |  | }
500 |  |
501 |  | /**
502 |  | * This implementation does actually use any features but just stores them
503 |  | * for later retrieval
504 |  | *
505 |  | * @param name
506 |  | * DOCUMENT ME!
507 |  | * @param value
508 |  | * DOCUMENT ME!
509 |  | *
510 |  | * @throws SAXNotRecognizedException
511 |  | * DOCUMENT ME!
512 |  | * @throws SAXNotSupportedException
513 |  | * DOCUMENT ME!
514 |  | */
515 | 8 | public void setFeature(String name, boolean value)
516 |  | throws SAXNotRecognizedException, SAXNotSupportedException {
517 | 8 | if (FEATURE_NAMESPACE_PREFIXES.equals(name)) {
518 | 8 | setDeclareNamespaceAttributes(value);
519 | 0 | } else if (FEATURE_NAMESPACE_PREFIXES.equals(name)) {
520 | 0 | if (!value) {
521 | 0 | String msg = "Namespace feature is always supported in dom4j";
522 | 0 | throw new SAXNotSupportedException(msg);
523 |  | }
524 |  | }
525 |  |
526 | 8 | features.put(name, (value) ? Boolean.TRUE : Boolean.FALSE);
527 |  | }
528 |  |
529 |  | /**
530 |  | * Sets the given SAX property
531 |  | *
532 |  | * @param name
533 |  | * DOCUMENT ME!
534 |  | * @param value
535 |  | * DOCUMENT ME!
536 |  | */
537 | 29 | public void setProperty(String name, Object value) {
538 | 29 | for (int i = 0; i < LEXICAL_HANDLER_NAMES.length; i++) {
539 | 50 | if (LEXICAL_HANDLER_NAMES[i].equals(name)) {
540 | 15 | setLexicalHandler((LexicalHandler) value);
541 |  |
542 | 15 | return;
543 |  | }
544 |  | }
545 |  |
546 | 14 | properties.put(name, value);
547 |  | }
548 |  |
549 |  | /**
550 |  | * Gets the given SAX property
551 |  | *
552 |  | * @param name
553 |  | * DOCUMENT ME!
554 |  | *
555 |  | * @return DOCUMENT ME!
556 |  | *
557 |  | * @throws SAXNotRecognizedException
558 |  | * DOCUMENT ME!
559 |  | * @throws SAXNotSupportedException
560 |  | * DOCUMENT ME!
561 |  | */
562 | 0 | public Object getProperty(String name) throws SAXNotRecognizedException,
563 |  | SAXNotSupportedException {
564 | 0 | for (int i = 0; i < LEXICAL_HANDLER_NAMES.length; i++) {
565 | 0 | if (LEXICAL_HANDLER_NAMES[i].equals(name)) {
566 | 0 | return getLexicalHandler();
567 |  | }
568 |  | }
569 |  |
570 | 0 | return properties.get(name);
571 |  | }
572 |  |
573 |  | /**
574 |  | * This method is not supported.
575 |  | *
576 |  | * @param systemId
577 |  | * DOCUMENT ME!
578 |  | *
579 |  | * @throws SAXNotSupportedException
580 |  | * DOCUMENT ME!
581 |  | */
582 | 0 | public void parse(String systemId) throws SAXNotSupportedException {
583 | 0 | throw new SAXNotSupportedException("This XMLReader can only accept"
584 |  | + " <dom4j> InputSource objects");
585 |  | }
586 |  |
587 |  | /**
588 |  | * Parses an XML document. This method can only accept DocumentInputSource
589 |  | * inputs otherwise a {@link SAXNotSupportedException}exception is thrown.
590 |  | *
591 |  | * @param input
592 |  | * DOCUMENT ME!
593 |  | *
594 |  | * @throws SAXException
595 |  | * DOCUMENT ME!
596 |  | * @throws SAXNotSupportedException
597 |  | * if the input source is not wrapping a dom4j document
598 |  | */
599 | 8 | public void parse(InputSource input) throws SAXException {
600 | 8 | if (input instanceof DocumentInputSource) {
601 | 8 | DocumentInputSource documentInput = (DocumentInputSource) input;
602 | 8 | Document document = documentInput.getDocument();
603 | 8 | write(document);
604 |  | } else {
605 | 0 | throw new SAXNotSupportedException(
606 |  | "This XMLReader can only accept "
607 |  | + "<dom4j> InputSource objects");
608 |  | }
609 |  | }
610 |  |
611 |  | // Implementation methods
612 |  | // -------------------------------------------------------------------------
613 | 4973 | protected void writeContent(Branch branch, NamespaceStack namespaceStack)
614 |  | throws SAXException {
615 | 4973 | for (Iterator iter = branch.nodeIterator(); iter.hasNext();) {
616 | 17227 | Object object = iter.next();
617 |  |
618 | 17227 | if (object instanceof Element) {
619 | 4953 | write((Element) object, namespaceStack);
620 | 12274 | } else if (object instanceof CharacterData) {
621 | 12233 | if (object instanceof Text) {
622 | 12132 | Text text = (Text) object;
623 | 12132 | write(text.getText());
624 | 101 | } else if (object instanceof CDATA) {
625 | 30 | write((CDATA) object);
626 | 71 | } else if (object instanceof Comment) {
627 | 71 | write((Comment) object);
628 |  | } else {
629 | 0 | throw new SAXException("Invalid Node in DOM4J content: "
630 |  | + object + " of type: " + object.getClass());
631 |  | }
632 | 41 | } else if (object instanceof String) {
633 | 0 | write((String) object);
634 | 41 | } else if (object instanceof Entity) {
635 | 0 | write((Entity) object);
636 | 41 | } else if (object instanceof ProcessingInstruction) {
637 | 2 | write((ProcessingInstruction) object);
638 | 39 | } else if (object instanceof Namespace) {
639 | 39 | write((Namespace) object);
640 |  | } else {
641 | 0 | throw new SAXException("Invalid Node in DOM4J content: "
642 |  | + object);
643 |  | }
644 |  | }
645 |  | }
646 |  |
647 |  | /**
648 |  | * The {@link org.xml.sax.Locator}is only really useful when parsing a
649 |  | * textual document as its main purpose is to identify the line and column
650 |  | * number. Since we are processing an in memory tree which will probably
651 |  | * have its line number information removed, we'll just use -1 for the line
652 |  | * and column numbers.
653 |  | *
654 |  | * @param document
655 |  | * DOCUMENT ME!
656 |  | *
657 |  | * @throws SAXException
658 |  | * DOCUMENT ME!
659 |  | */
660 | 20 | protected void documentLocator(Document document) throws SAXException {
661 | 20 | LocatorImpl locator = new LocatorImpl();
662 |  |
663 | 20 | String publicID = null;
664 | 20 | String systemID = null;
665 | 20 | DocumentType docType = document.getDocType();
666 |  |
667 | 20 | if (docType != null) {
668 | 0 | publicID = docType.getPublicID();
669 | 0 | systemID = docType.getSystemID();
670 |  | }
671 |  |
672 | 20 | if (publicID != null) {
673 | 0 | locator.setPublicId(publicID);
674 |  | }
675 |  |
676 | 20 | if (systemID != null) {
677 | 0 | locator.setSystemId(systemID);
678 |  | }
679 |  |
680 | 20 | locator.setLineNumber(-1);
681 | 20 | locator.setColumnNumber(-1);
682 |  |
683 | 20 | contentHandler.setDocumentLocator(locator);
684 |  | }
685 |  |
686 | 20 | protected void entityResolver(Document document) throws SAXException {
687 | 20 | if (entityResolver != null) {
688 | 12 | DocumentType docType = document.getDocType();
689 |  |
690 | 12 | if (docType != null) {
691 | 0 | String publicID = docType.getPublicID();
692 | 0 | String systemID = docType.getSystemID();
693 |  |
694 | 0 | if ((publicID != null) || (systemID != null)) {
695 | 0 | try {
696 | 0 | entityResolver.resolveEntity(publicID, systemID);
697 |  | } catch (IOException e) {
698 | 0 | throw new SAXException("Could not resolve publicID: "
699 |  | + publicID + " systemID: " + systemID, e);
700 |  | }
701 |  | }
702 |  | }
703 |  | }
704 |  | }
705 |  |
706 |  | /**
707 |  | * We do not yet support DTD or XML Schemas so this method does nothing
708 |  | * right now.
709 |  | *
710 |  | * @param document
711 |  | * DOCUMENT ME!
712 |  | *
713 |  | * @throws SAXException
714 |  | * DOCUMENT ME!
715 |  | */
716 | 20 | protected void dtdHandler(Document document) throws SAXException {
717 |  | }
718 |  |
719 | 20 | protected void startDocument() throws SAXException {
720 | 20 | contentHandler.startDocument();
721 |  | }
722 |  |
723 | 20 | protected void endDocument() throws SAXException {
724 | 20 | contentHandler.endDocument();
725 |  | }
726 |  |
727 | 4953 | protected void write(Element element, NamespaceStack namespaceStack)
728 |  | throws SAXException {
729 | 4953 | int stackSize = namespaceStack.size();
730 | 4953 | AttributesImpl namespaceAttributes = startPrefixMapping(element,
731 |  | namespaceStack);
732 | 4953 | startElement(element, namespaceAttributes);
733 | 4953 | writeContent(element, namespaceStack);
734 | 4953 | endElement(element);
735 | 4953 | endPrefixMapping(namespaceStack, stackSize);
736 |  | }
737 |  |
738 |  | /**
739 |  | * Fires a SAX startPrefixMapping event for all the namespaceStack which
740 |  | * have just come into scope
741 |  | *
742 |  | * @param element
743 |  | * DOCUMENT ME!
744 |  | * @param namespaceStack
745 |  | * DOCUMENT ME!
746 |  | *
747 |  | * @return DOCUMENT ME!
748 |  | *
749 |  | * @throws SAXException
750 |  | * DOCUMENT ME!
751 |  | */
752 | 4953 | protected AttributesImpl startPrefixMapping(Element element,
753 |  | NamespaceStack namespaceStack) throws SAXException {
754 | 4953 | AttributesImpl namespaceAttributes = null;
755 |  |
756 |  | // start with the namespace of the element
757 | 4953 | Namespace elementNamespace = element.getNamespace();
758 |  |
759 | 4953 | if ((elementNamespace != null)
760 |  | && !isIgnoreableNamespace(elementNamespace, namespaceStack)) {
761 | 36 | namespaceStack.push(elementNamespace);
762 | 36 | contentHandler.startPrefixMapping(elementNamespace.getPrefix(),
763 |  | elementNamespace.getURI());
764 | 36 | namespaceAttributes = addNamespaceAttribute(namespaceAttributes,
765 |  | elementNamespace);
766 |  | }
767 |  |
768 | 4953 | List declaredNamespaces = element.declaredNamespaces();
769 |  |
770 | 4953 | for (int i = 0, size = declaredNamespaces.size(); i < size; i++) {
771 | 39 | Namespace namespace = (Namespace) declaredNamespaces.get(i);
772 |  |
773 | 39 | if (!isIgnoreableNamespace(namespace, namespaceStack)) {
774 | 3 | namespaceStack.push(namespace);
775 | 3 | contentHandler.startPrefixMapping(namespace.getPrefix(),
776 |  | namespace.getURI());
777 | 3 | namespaceAttributes = addNamespaceAttribute(
778 |  | namespaceAttributes, namespace);
779 |  | }
780 |  | }
781 |  |
782 | 4953 | return namespaceAttributes;
783 |  | }
784 |  |
785 |  | /**
786 |  | * Fires a SAX endPrefixMapping event for all the namespaceStack which have
787 |  | * gone out of scope
788 |  | *
789 |  | * @param stack
790 |  | * DOCUMENT ME!
791 |  | * @param stackSize
792 |  | * DOCUMENT ME!
793 |  | *
794 |  | * @throws SAXException
795 |  | * DOCUMENT ME!
796 |  | */
797 | 4953 | protected void endPrefixMapping(NamespaceStack stack, int stackSize)
798 |  | throws SAXException {
799 | 4953 | while (stack.size() > stackSize) {
800 | 39 | Namespace namespace = stack.pop();
801 |  |
802 | 39 | if (namespace != null) {
803 | 39 | contentHandler.endPrefixMapping(namespace.getPrefix());
804 |  | }
805 |  | }
806 |  | }
807 |  |
808 | 4953 | protected void startElement(Element element,
809 |  | AttributesImpl namespaceAttributes) throws SAXException {
810 | 4953 | contentHandler.startElement(element.getNamespaceURI(), element
811 |  | .getName(), element.getQualifiedName(), createAttributes(
812 |  | element, namespaceAttributes));
813 |  | }
814 |  |
815 | 4953 | protected void endElement(Element element) throws SAXException {
816 | 4953 | contentHandler.endElement(element.getNamespaceURI(), element.getName(),
817 |  | element.getQualifiedName());
818 |  | }
819 |  |
820 | 4953 | protected Attributes createAttributes(Element element,
821 |  | Attributes namespaceAttributes) throws SAXException {
822 | 4953 | attributes.clear();
823 |  |
824 | 4953 | if (namespaceAttributes != null) {
825 | 12 | attributes.setAttributes(namespaceAttributes);
826 |  | }
827 |  |
828 | 4953 | for (Iterator iter = element.attributeIterator(); iter.hasNext();) {
829 | 2609 | Attribute attribute = (Attribute) iter.next();
830 | 2609 | attributes.addAttribute(attribute.getNamespaceURI(), attribute
831 |  | .getName(), attribute.getQualifiedName(), "CDATA",
832 |  | attribute.getValue());
833 |  | }
834 |  |
835 | 4953 | return attributes;
836 |  | }
837 |  |
838 |  | /**
839 |  | * If isDelcareNamespaceAttributes() is enabled then this method will add
840 |  | * the given namespace declaration to the supplied attributes object,
841 |  | * creating one if it does not exist.
842 |  | *
843 |  | * @param attrs
844 |  | * DOCUMENT ME!
845 |  | * @param namespace
846 |  | * DOCUMENT ME!
847 |  | *
848 |  | * @return DOCUMENT ME!
849 |  | */
850 | 39 | protected AttributesImpl addNamespaceAttribute(AttributesImpl attrs,
851 |  | Namespace namespace) {
852 | 39 | if (declareNamespaceAttributes) {
853 | 13 | if (attrs == null) {
854 | 12 | attrs = new AttributesImpl();
855 |  | }
856 |  |
857 | 13 | String prefix = namespace.getPrefix();
858 | 13 | String qualifiedName = "xmlns";
859 |  |
860 | 13 | if ((prefix != null) && (prefix.length() > 0)) {
861 | 8 | qualifiedName = "xmlns:" + prefix;
862 |  | }
863 |  |
864 | 13 | String uri = "";
865 | 13 | String localName = prefix;
866 | 13 | String type = "CDATA";
867 | 13 | String value = namespace.getURI();
868 |  |
869 | 13 | attrs.addAttribute(uri, localName, qualifiedName, type, value);
870 |  | }
871 |  |
872 | 39 | return attrs;
873 |  | }
874 |  |
875 |  | /**
876 |  | * DOCUMENT ME!
877 |  | *
878 |  | * @param namespace
879 |  | * DOCUMENT ME!
880 |  | * @param namespaceStack
881 |  | * DOCUMENT ME!
882 |  | *
883 |  | * @return true if the given namespace is an ignorable namespace (such as
884 |  | * Namespace.NO_NAMESPACE or Namespace.XML_NAMESPACE) or if the
885 |  | * namespace has already been declared in the current scope
886 |  | */
887 | 4992 | protected boolean isIgnoreableNamespace(Namespace namespace,
888 |  | NamespaceStack namespaceStack) {
889 | 4992 | if (namespace.equals(Namespace.NO_NAMESPACE)
890 |  | || namespace.equals(Namespace.XML_NAMESPACE)) {
891 | 4761 | return true;
892 |  | }
893 |  |
894 | 231 | String uri = namespace.getURI();
895 |  |
896 | 231 | if ((uri == null) || (uri.length() <= 0)) {
897 | 0 | return true;
898 |  | }
899 |  |
900 | 231 | return namespaceStack.contains(namespace);
901 |  | }
902 |  |
903 |  | /**
904 |  | * Ensures non-null content handlers?
905 |  | */
906 | 20 | protected void checkForNullHandlers() {
907 |  | }
908 |  | }
909 |  |
910 |  | /*
911 |  | * Redistribution and use of this software and associated documentation
912 |  | * ("Software"), with or without modification, are permitted provided that the
913 |  | * following conditions are met:
914 |  | *
915 |  | * 1. Redistributions of source code must retain copyright statements and
916 |  | * notices. Redistributions must also contain a copy of this document.
917 |  | *
918 |  | * 2. Redistributions in binary form must reproduce the above copyright notice,
919 |  | * this list of conditions and the following disclaimer in the documentation
920 |  | * and/or other materials provided with the distribution.
921 |  | *
922 |  | * 3. The name "DOM4J" must not be used to endorse or promote products derived
923 |  | * from this Software without prior written permission of MetaStuff, Ltd. For
924 |  | * written permission, please contact dom4j-info@metastuff.com.
925 |  | *
926 |  | * 4. Products derived from this Software may not be called "DOM4J" nor may
927 |  | * "DOM4J" appear in their names without prior written permission of MetaStuff,
928 |  | * Ltd. DOM4J is a registered trademark of MetaStuff, Ltd.
929 |  | *
930 |  | * 5. Due credit should be given to the DOM4J Project - http://www.dom4j.org
931 |  | *
932 |  | * THIS SOFTWARE IS PROVIDED BY METASTUFF, LTD. AND CONTRIBUTORS ``AS IS'' AND
933 |  | * ANY EXPRESSED OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
934 |  | * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
935 |  | * ARE DISCLAIMED. IN NO EVENT SHALL METASTUFF, LTD. OR ITS CONTRIBUTORS BE
936 |  | * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
937 |  | * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
938 |  | * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
939 |  | * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
940 |  | * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
941 |  | * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
942 |  | * POSSIBILITY OF SUCH DAMAGE.
943 |  | *
944 |  | * Copyright 2001-2005 (C) MetaStuff, Ltd. All Rights Reserved.
945 |  | */