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