1
2
3
4
5
6
7
8 package org.dom4j.io;
9
10 import java.lang.reflect.Method;
11 import java.util.ArrayList;
12 import java.util.HashMap;
13 import java.util.List;
14 import java.util.Map;
15
16 import org.dom4j.Branch;
17 import org.dom4j.Document;
18 import org.dom4j.DocumentFactory;
19 import org.dom4j.DocumentType;
20 import org.dom4j.Element;
21 import org.dom4j.ElementHandler;
22 import org.dom4j.Namespace;
23 import org.dom4j.QName;
24 import org.dom4j.dtd.AttributeDecl;
25 import org.dom4j.dtd.ElementDecl;
26 import org.dom4j.dtd.ExternalEntityDecl;
27 import org.dom4j.dtd.InternalEntityDecl;
28 import org.dom4j.tree.AbstractElement;
29 import org.dom4j.tree.NamespaceStack;
30
31 import org.xml.sax.Attributes;
32 import org.xml.sax.DTDHandler;
33 import org.xml.sax.EntityResolver;
34 import org.xml.sax.InputSource;
35 import org.xml.sax.Locator;
36 import org.xml.sax.SAXException;
37 import org.xml.sax.SAXParseException;
38 import org.xml.sax.ext.DeclHandler;
39 import org.xml.sax.ext.LexicalHandler;
40 import org.xml.sax.helpers.DefaultHandler;
41
42 /***
43 * <p>
44 * <code>SAXContentHandler</code> builds a dom4j tree via SAX events.
45 * </p>
46 *
47 * @author <a href="mailto:jstrachan@apache.org">James Strachan </a>
48 * @version $Revision: 1.61 $
49 */
50 public class SAXContentHandler extends DefaultHandler implements
51 LexicalHandler, DeclHandler, DTDHandler {
52 /*** The factory used to create new <code>Document</code> instances */
53 private DocumentFactory documentFactory;
54
55 /*** The document that is being built */
56 private Document document;
57
58 /*** stack of <code>Element</code> objects */
59 private ElementStack elementStack;
60
61 /*** stack of <code>Namespace</code> and <code>QName</code> objects */
62 private NamespaceStack namespaceStack;
63
64 /*** the <code>ElementHandler</code> called as the elements are complete */
65 private ElementHandler elementHandler;
66
67 /*** the Locator */
68 private Locator locator;
69
70 /*** The name of the current entity */
71 private String entity;
72
73 /*** Flag used to indicate that we are inside a DTD section */
74 private boolean insideDTDSection;
75
76 /*** Flag used to indicate that we are inside a CDATA section */
77 private boolean insideCDATASection;
78
79 /***
80 * buffer to hold contents of cdata section across multiple characters
81 * events
82 */
83 private StringBuffer cdataText;
84
85 /*** namespaces that are available for use */
86 private Map availableNamespaceMap = new HashMap();
87
88 /*** declared namespaces that are not yet available for use */
89 private List declaredNamespaceList = new ArrayList();
90
91 /*** internal DTD declarations */
92 private List internalDTDDeclarations;
93
94 /*** external DTD declarations */
95 private List externalDTDDeclarations;
96
97 /*** The number of namespaces that are declared in the current scope */
98 private int declaredNamespaceIndex;
99
100 /*** The entity resolver */
101 private EntityResolver entityResolver;
102
103 private InputSource inputSource;
104
105 /*** The current element we are on */
106 private Element currentElement;
107
108 /*** Should internal DTD declarations be expanded into a List in the DTD */
109 private boolean includeInternalDTDDeclarations = false;
110
111 /*** Should external DTD declarations be expanded into a List in the DTD */
112 private boolean includeExternalDTDDeclarations = false;
113
114 /*** The number of levels deep we are inside a startEntity/endEntity call */
115 private int entityLevel;
116
117 /*** Are we in an internal DTD subset? */
118 private boolean internalDTDsubset = false;
119
120 /*** Whether adjacent text nodes should be merged */
121 private boolean mergeAdjacentText = false;
122
123 /*** Have we added text to the buffer */
124 private boolean textInTextBuffer = false;
125
126 /*** Should we ignore comments */
127 private boolean ignoreComments = false;
128
129 /*** Buffer used to concatenate text together */
130 private StringBuffer textBuffer;
131
132 /*** Holds value of property stripWhitespaceText. */
133 private boolean stripWhitespaceText = false;
134
135 public SAXContentHandler() {
136 this(DocumentFactory.getInstance());
137 }
138
139 public SAXContentHandler(DocumentFactory documentFactory) {
140 this(documentFactory, null);
141 }
142
143 public SAXContentHandler(DocumentFactory documentFactory,
144 ElementHandler elementHandler) {
145 this(documentFactory, elementHandler, null);
146 this.elementStack = createElementStack();
147 }
148
149 public SAXContentHandler(DocumentFactory documentFactory,
150 ElementHandler elementHandler, ElementStack elementStack) {
151 this.documentFactory = documentFactory;
152 this.elementHandler = elementHandler;
153 this.elementStack = elementStack;
154 this.namespaceStack = new NamespaceStack(documentFactory);
155 }
156
157 /***
158 * DOCUMENT ME!
159 *
160 * @return the document that has been or is being built
161 */
162 public Document getDocument() {
163 if (document == null) {
164 document = createDocument();
165 }
166
167 return document;
168 }
169
170
171
172 public void setDocumentLocator(Locator documentLocator) {
173 this.locator = documentLocator;
174 }
175
176 public void processingInstruction(String target, String data)
177 throws SAXException {
178 if (mergeAdjacentText && textInTextBuffer) {
179 completeCurrentTextNode();
180 }
181
182 if (currentElement != null) {
183 currentElement.addProcessingInstruction(target, data);
184 } else {
185 getDocument().addProcessingInstruction(target, data);
186 }
187 }
188
189 public void startPrefixMapping(String prefix, String uri)
190 throws SAXException {
191 namespaceStack.push(prefix, uri);
192 }
193
194 public void endPrefixMapping(String prefix) throws SAXException {
195 namespaceStack.pop(prefix);
196 declaredNamespaceIndex = namespaceStack.size();
197 }
198
199 public void startDocument() throws SAXException {
200
201 document = null;
202 currentElement = null;
203
204 elementStack.clear();
205
206 if ((elementHandler != null)
207 && (elementHandler instanceof DispatchHandler)) {
208 elementStack.setDispatchHandler((DispatchHandler) elementHandler);
209 }
210
211 namespaceStack.clear();
212 declaredNamespaceIndex = 0;
213
214 if (mergeAdjacentText && (textBuffer == null)) {
215 textBuffer = new StringBuffer();
216 }
217
218 textInTextBuffer = false;
219 }
220
221 public void endDocument() throws SAXException {
222 namespaceStack.clear();
223 elementStack.clear();
224 currentElement = null;
225 textBuffer = null;
226 }
227
228 public void startElement(String namespaceURI, String localName,
229 String qualifiedName, Attributes attributes) throws SAXException {
230 if (mergeAdjacentText && textInTextBuffer) {
231 completeCurrentTextNode();
232 }
233
234 QName qName = namespaceStack.getQName(namespaceURI, localName,
235 qualifiedName);
236
237 Branch branch = currentElement;
238
239 if (branch == null) {
240 branch = getDocument();
241 }
242
243 Element element = branch.addElement(qName);
244
245
246 addDeclaredNamespaces(element);
247
248
249 addAttributes(element, attributes);
250
251 elementStack.pushElement(element);
252 currentElement = element;
253
254 entity = null;
255
256 if (elementHandler != null) {
257 elementHandler.onStart(elementStack);
258 }
259 }
260
261 public void endElement(String namespaceURI, String localName, String qName)
262 throws SAXException {
263 if (mergeAdjacentText && textInTextBuffer) {
264 completeCurrentTextNode();
265 }
266
267 if ((elementHandler != null) && (currentElement != null)) {
268 elementHandler.onEnd(elementStack);
269 }
270
271 elementStack.popElement();
272 currentElement = elementStack.peekElement();
273 }
274
275 public void characters(char[] ch, int start, int end) throws SAXException {
276 if (end == 0) {
277 return;
278 }
279
280 if (currentElement != null) {
281 if (entity != null) {
282 if (mergeAdjacentText && textInTextBuffer) {
283 completeCurrentTextNode();
284 }
285
286 currentElement.addEntity(entity, new String(ch, start, end));
287 entity = null;
288 } else if (insideCDATASection) {
289 if (mergeAdjacentText && textInTextBuffer) {
290 completeCurrentTextNode();
291 }
292
293 cdataText.append(new String(ch, start, end));
294 } else {
295 if (mergeAdjacentText) {
296 textBuffer.append(ch, start, end);
297 textInTextBuffer = true;
298 } else {
299 currentElement.addText(new String(ch, start, end));
300 }
301 }
302 }
303 }
304
305
306
307
308 /***
309 * This method is called when a warning occurs during the parsing of the
310 * document. This method does nothing.
311 *
312 * @param exception
313 * DOCUMENT ME!
314 *
315 * @throws SAXException
316 * DOCUMENT ME!
317 */
318 public void warning(SAXParseException exception) throws SAXException {
319
320 }
321
322 /***
323 * This method is called when an error is detected during parsing such as a
324 * validation error. This method rethrows the exception
325 *
326 * @param exception
327 * DOCUMENT ME!
328 *
329 * @throws SAXException
330 * DOCUMENT ME!
331 */
332 public void error(SAXParseException exception) throws SAXException {
333 throw exception;
334 }
335
336 /***
337 * This method is called when a fatal error occurs during parsing. This
338 * method rethrows the exception
339 *
340 * @param exception
341 * DOCUMENT ME!
342 *
343 * @throws SAXException
344 * DOCUMENT ME!
345 */
346 public void fatalError(SAXParseException exception) throws SAXException {
347 throw exception;
348 }
349
350
351
352 public void startDTD(String name, String publicId, String systemId)
353 throws SAXException {
354 getDocument().addDocType(name, publicId, systemId);
355 insideDTDSection = true;
356 internalDTDsubset = true;
357 }
358
359 public void endDTD() throws SAXException {
360 insideDTDSection = false;
361
362 DocumentType docType = getDocument().getDocType();
363
364 if (docType != null) {
365 if (internalDTDDeclarations != null) {
366 docType.setInternalDeclarations(internalDTDDeclarations);
367 }
368
369 if (externalDTDDeclarations != null) {
370 docType.setExternalDeclarations(externalDTDDeclarations);
371 }
372 }
373
374 internalDTDDeclarations = null;
375 externalDTDDeclarations = null;
376 }
377
378 public void startEntity(String name) throws SAXException {
379 ++entityLevel;
380
381
382 entity = null;
383
384 if (!insideDTDSection) {
385 if (!isIgnorableEntity(name)) {
386 entity = name;
387 }
388 }
389
390
391
392
393
394 internalDTDsubset = false;
395 }
396
397 public void endEntity(String name) throws SAXException {
398 --entityLevel;
399 entity = null;
400
401 if (entityLevel == 0) {
402 internalDTDsubset = true;
403 }
404 }
405
406 public void startCDATA() throws SAXException {
407 insideCDATASection = true;
408 cdataText = new StringBuffer();
409 }
410
411 public void endCDATA() throws SAXException {
412 insideCDATASection = false;
413 currentElement.addCDATA(cdataText.toString());
414 }
415
416 public void comment(char[] ch, int start, int end) throws SAXException {
417 if (!ignoreComments) {
418 if (mergeAdjacentText && textInTextBuffer) {
419 completeCurrentTextNode();
420 }
421
422 String text = new String(ch, start, end);
423
424 if (!insideDTDSection && (text.length() > 0)) {
425 if (currentElement != null) {
426 currentElement.addComment(text);
427 } else {
428 getDocument().addComment(text);
429 }
430 }
431 }
432 }
433
434
435
436
437 /***
438 * Report an element type declaration.
439 *
440 * <p>
441 * The content model will consist of the string "EMPTY", the string "ANY",
442 * or a parenthesised group, optionally followed by an occurrence indicator.
443 * The model will be normalized so that all parameter entities are fully
444 * resolved and all whitespace is removed,and will include the enclosing
445 * parentheses. Other normalization (such as removing redundant parentheses
446 * or simplifying occurrence indicators) is at the discretion of the parser.
447 * </p>
448 *
449 * @param name
450 * The element type name.
451 * @param model
452 * The content model as a normalized string.
453 *
454 * @exception SAXException
455 * The application may raise an exception.
456 */
457 public void elementDecl(String name, String model) throws SAXException {
458 if (internalDTDsubset) {
459 if (includeInternalDTDDeclarations) {
460 addDTDDeclaration(new ElementDecl(name, model));
461 }
462 } else {
463 if (includeExternalDTDDeclarations) {
464 addExternalDTDDeclaration(new ElementDecl(name, model));
465 }
466 }
467 }
468
469 /***
470 * Report an attribute type declaration.
471 *
472 * <p>
473 * Only the effective (first) declaration for an attribute will be reported.
474 * The type will be one of the strings "CDATA", "ID", "IDREF", "IDREFS",
475 * "NMTOKEN", "NMTOKENS", "ENTITY", "ENTITIES", a parenthesized token group
476 * with the separator "|" and all whitespace removed, or the word "NOTATION"
477 * followed by a space followed by a parenthesized token group with all
478 * whitespace removed.
479 * </p>
480 *
481 * <p>
482 * Any parameter entities in the attribute value will be expanded, but
483 * general entities will not.
484 * </p>
485 *
486 * @param eName
487 * The name of the associated element.
488 * @param aName
489 * The name of the attribute.
490 * @param type
491 * A string representing the attribute type.
492 * @param valueDefault
493 * A string representing the attribute default ("#IMPLIED",
494 * "#REQUIRED", or "#FIXED") or null if none of these applies.
495 * @param val
496 * A string representing the attribute's default value, or null
497 * if there is none.
498 *
499 * @exception SAXException
500 * The application may raise an exception.
501 */
502 public void attributeDecl(String eName, String aName, String type,
503 String valueDefault, String val) throws SAXException {
504 if (internalDTDsubset) {
505 if (includeInternalDTDDeclarations) {
506 addDTDDeclaration(new AttributeDecl(eName, aName, type,
507 valueDefault, val));
508 }
509 } else {
510 if (includeExternalDTDDeclarations) {
511 addExternalDTDDeclaration(new AttributeDecl(eName, aName, type,
512 valueDefault, val));
513 }
514 }
515 }
516
517 /***
518 * Report an internal entity declaration.
519 *
520 * <p>
521 * Only the effective (first) declaration for each entity will be reported.
522 * All parameter entities in the value will be expanded, but general
523 * entities will not.
524 * </p>
525 *
526 * @param name
527 * The name of the entity. If it is a parameter entity, the name
528 * will begin with '%'.
529 * @param value
530 * The replacement text of the entity.
531 *
532 * @exception SAXException
533 * The application may raise an exception.
534 *
535 * @see #externalEntityDecl
536 * @see org.xml.sax.DTDHandler#unparsedEntityDecl
537 */
538 public void internalEntityDecl(String name, String value)
539 throws SAXException {
540 if (internalDTDsubset) {
541 if (includeInternalDTDDeclarations) {
542 addDTDDeclaration(new InternalEntityDecl(name, value));
543 }
544 } else {
545 if (includeExternalDTDDeclarations) {
546 addExternalDTDDeclaration(new InternalEntityDecl(name, value));
547 }
548 }
549 }
550
551 /***
552 * Report a parsed external entity declaration.
553 *
554 * <p>
555 * Only the effective (first) declaration for each entity will be reported.
556 * </p>
557 *
558 * @param name
559 * The name of the entity. If it is a parameter entity, the name
560 * will begin with '%'.
561 * @param publicId
562 * The declared public identifier of the entity, or null if none
563 * was declared.
564 * @param sysId
565 * The declared system identifier of the entity.
566 *
567 * @exception SAXException
568 * The application may raise an exception.
569 *
570 * @see #internalEntityDecl
571 * @see org.xml.sax.DTDHandler#unparsedEntityDecl
572 */
573 public void externalEntityDecl(String name, String publicId, String sysId)
574 throws SAXException {
575 ExternalEntityDecl declaration = new ExternalEntityDecl(name, publicId,
576 sysId);
577
578 if (internalDTDsubset) {
579 if (includeInternalDTDDeclarations) {
580 addDTDDeclaration(declaration);
581 }
582 } else {
583 if (includeExternalDTDDeclarations) {
584 addExternalDTDDeclaration(declaration);
585 }
586 }
587 }
588
589
590
591
592 /***
593 * Receive notification of a notation declaration event.
594 *
595 * <p>
596 * It is up to the application to record the notation for later reference,
597 * if necessary.
598 * </p>
599 *
600 * <p>
601 * At least one of publicId and systemId must be non-null. If a system
602 * identifier is present, and it is a URL, the SAX parser must resolve it
603 * fully before passing it to the application through this event.
604 * </p>
605 *
606 * <p>
607 * There is no guarantee that the notation declaration will be reported
608 * before any unparsed entities that use it.
609 * </p>
610 *
611 * @param name
612 * The notation name.
613 * @param publicId
614 * The notation's public identifier, or null if none was given.
615 * @param systemId
616 * The notation's system identifier, or null if none was given.
617 *
618 * @exception SAXException
619 * Any SAX exception, possibly wrapping another exception.
620 *
621 * @see #unparsedEntityDecl
622 * @see org.xml.sax.AttributeList
623 */
624 public void notationDecl(String name, String publicId, String systemId)
625 throws SAXException {
626
627 }
628
629 /***
630 * Receive notification of an unparsed entity declaration event.
631 *
632 * <p>
633 * Note that the notation name corresponds to a notation reported by the
634 * {@link #notationDecl notationDecl}event. It is up to the application to
635 * record the entity for later reference, if necessary.
636 * </p>
637 *
638 * <p>
639 * If the system identifier is a URL, the parser must resolve it fully
640 * before passing it to the application.
641 * </p>
642 *
643 * @param name
644 * The unparsed entity's name.
645 * @param publicId
646 * The entity's public identifier, or null if none was given.
647 * @param systemId
648 * The entity's system identifier.
649 * @param notationName
650 * The name of the associated notation.
651 *
652 * @exception SAXException
653 * Any SAX exception, possibly wrapping another exception.
654 *
655 * @see #notationDecl
656 * @see org.xml.sax.AttributeList
657 */
658 public void unparsedEntityDecl(String name, String publicId,
659 String systemId, String notationName) throws SAXException {
660
661 }
662
663
664
665 public ElementStack getElementStack() {
666 return elementStack;
667 }
668
669 public void setElementStack(ElementStack elementStack) {
670 this.elementStack = elementStack;
671 }
672
673 public EntityResolver getEntityResolver() {
674 return entityResolver;
675 }
676
677 public void setEntityResolver(EntityResolver entityResolver) {
678 this.entityResolver = entityResolver;
679 }
680
681 public InputSource getInputSource() {
682 return inputSource;
683 }
684
685 public void setInputSource(InputSource inputSource) {
686 this.inputSource = inputSource;
687 }
688
689 /***
690 * DOCUMENT ME!
691 *
692 * @return whether internal DTD declarations should be expanded into the
693 * DocumentType object or not.
694 */
695 public boolean isIncludeInternalDTDDeclarations() {
696 return includeInternalDTDDeclarations;
697 }
698
699 /***
700 * Sets whether internal DTD declarations should be expanded into the
701 * DocumentType object or not.
702 *
703 * @param include
704 * whether or not DTD declarations should be expanded and
705 * included into the DocumentType object.
706 */
707 public void setIncludeInternalDTDDeclarations(boolean include) {
708 this.includeInternalDTDDeclarations = include;
709 }
710
711 /***
712 * DOCUMENT ME!
713 *
714 * @return whether external DTD declarations should be expanded into the
715 * DocumentType object or not.
716 */
717 public boolean isIncludeExternalDTDDeclarations() {
718 return includeExternalDTDDeclarations;
719 }
720
721 /***
722 * Sets whether DTD external declarations should be expanded into the
723 * DocumentType object or not.
724 *
725 * @param include
726 * whether or not DTD declarations should be expanded and
727 * included into the DocumentType object.
728 */
729 public void setIncludeExternalDTDDeclarations(boolean include) {
730 this.includeExternalDTDDeclarations = include;
731 }
732
733 /***
734 * Returns whether adjacent text nodes should be merged together.
735 *
736 * @return Value of property mergeAdjacentText.
737 */
738 public boolean isMergeAdjacentText() {
739 return mergeAdjacentText;
740 }
741
742 /***
743 * Sets whether or not adjacent text nodes should be merged together when
744 * parsing.
745 *
746 * @param mergeAdjacentText
747 * New value of property mergeAdjacentText.
748 */
749 public void setMergeAdjacentText(boolean mergeAdjacentText) {
750 this.mergeAdjacentText = mergeAdjacentText;
751 }
752
753 /***
754 * Sets whether whitespace between element start and end tags should be
755 * ignored
756 *
757 * @return Value of property stripWhitespaceText.
758 */
759 public boolean isStripWhitespaceText() {
760 return stripWhitespaceText;
761 }
762
763 /***
764 * Sets whether whitespace between element start and end tags should be
765 * ignored.
766 *
767 * @param stripWhitespaceText
768 * New value of property stripWhitespaceText.
769 */
770 public void setStripWhitespaceText(boolean stripWhitespaceText) {
771 this.stripWhitespaceText = stripWhitespaceText;
772 }
773
774 /***
775 * Returns whether we should ignore comments or not.
776 *
777 * @return boolean
778 */
779 public boolean isIgnoreComments() {
780 return ignoreComments;
781 }
782
783 /***
784 * Sets whether we should ignore comments or not.
785 *
786 * @param ignoreComments
787 * whether we should ignore comments or not.
788 */
789 public void setIgnoreComments(boolean ignoreComments) {
790 this.ignoreComments = ignoreComments;
791 }
792
793
794
795
796 /***
797 * If the current text buffer contains any text then create a new text node
798 * with it and add it to the current element
799 */
800 protected void completeCurrentTextNode() {
801 if (stripWhitespaceText) {
802 boolean whitespace = true;
803
804 for (int i = 0, size = textBuffer.length(); i < size; i++) {
805 if (!Character.isWhitespace(textBuffer.charAt(i))) {
806 whitespace = false;
807
808 break;
809 }
810 }
811
812 if (!whitespace) {
813 currentElement.addText(textBuffer.toString());
814 }
815 } else {
816 currentElement.addText(textBuffer.toString());
817 }
818
819 textBuffer.setLength(0);
820 textInTextBuffer = false;
821 }
822
823 /***
824 * DOCUMENT ME!
825 *
826 * @return the current document
827 */
828 protected Document createDocument() {
829 String encoding = getEncoding();
830 Document doc = documentFactory.createDocument(encoding);
831
832
833 doc.setEntityResolver(entityResolver);
834
835 if (inputSource != null) {
836 doc.setName(inputSource.getSystemId());
837 }
838
839 return doc;
840 }
841
842 private String getEncoding() {
843 if (locator == null) {
844 return null;
845 }
846
847
848
849 try {
850 Method m = locator.getClass().getMethod("getEncoding",
851 new Class[] {});
852
853 if (m != null) {
854 return (String) m.invoke(locator, null);
855 }
856 } catch (Exception e) {
857
858 }
859
860
861 return null;
862 }
863
864 /***
865 * a Strategy Method to determine if a given entity name is ignorable
866 *
867 * @param name
868 * DOCUMENT ME!
869 *
870 * @return DOCUMENT ME!
871 */
872 protected boolean isIgnorableEntity(String name) {
873 return "amp".equals(name) || "apos".equals(name) || "gt".equals(name)
874 || "lt".equals(name) || "quot".equals(name);
875 }
876
877 /***
878 * Add all namespaces declared before the startElement() SAX event to the
879 * current element so that they are available to child elements and
880 * attributes
881 *
882 * @param element
883 * DOCUMENT ME!
884 */
885 protected void addDeclaredNamespaces(Element element) {
886 Namespace elementNamespace = element.getNamespace();
887
888 for (int size = namespaceStack.size(); declaredNamespaceIndex < size;
889 declaredNamespaceIndex++) {
890 Namespace namespace = namespaceStack
891 .getNamespace(declaredNamespaceIndex);
892
893
894 element.add(namespace);
895
896
897 }
898 }
899
900 /***
901 * Add all the attributes to the given elements
902 *
903 * @param element
904 * DOCUMENT ME!
905 * @param attributes
906 * DOCUMENT ME!
907 */
908 protected void addAttributes(Element element, Attributes attributes) {
909
910
911 boolean noNamespaceAttributes = false;
912
913 if (element instanceof AbstractElement) {
914
915 AbstractElement baseElement = (AbstractElement) element;
916 baseElement.setAttributes(attributes, namespaceStack,
917 noNamespaceAttributes);
918 } else {
919 int size = attributes.getLength();
920
921 for (int i = 0; i < size; i++) {
922 String attributeQName = attributes.getQName(i);
923
924 if (noNamespaceAttributes
925 || !attributeQName.startsWith("xmlns")) {
926 String attributeURI = attributes.getURI(i);
927 String attributeLocalName = attributes.getLocalName(i);
928 String attributeValue = attributes.getValue(i);
929
930 QName qName = namespaceStack.getAttributeQName(
931 attributeURI, attributeLocalName, attributeQName);
932 element.addAttribute(qName, attributeValue);
933 }
934 }
935 }
936 }
937
938 /***
939 * Adds an internal DTD declaration to the list of declarations
940 *
941 * @param declaration
942 * DOCUMENT ME!
943 */
944 protected void addDTDDeclaration(Object declaration) {
945 if (internalDTDDeclarations == null) {
946 internalDTDDeclarations = new ArrayList();
947 }
948
949 internalDTDDeclarations.add(declaration);
950 }
951
952 /***
953 * Adds an external DTD declaration to the list of declarations
954 *
955 * @param declaration
956 * DOCUMENT ME!
957 */
958 protected void addExternalDTDDeclaration(Object declaration) {
959 if (externalDTDDeclarations == null) {
960 externalDTDDeclarations = new ArrayList();
961 }
962
963 externalDTDDeclarations.add(declaration);
964 }
965
966 protected ElementStack createElementStack() {
967 return new ElementStack();
968 }
969 }
970
971
972
973
974
975
976
977
978
979
980
981
982
983
984
985
986
987
988
989
990
991
992
993
994
995
996
997
998
999
1000
1001
1002
1003
1004
1005
1006