1   
2   
3   
4   
5   
6   
7   
8   package org.dom4j.io;
9   
10  import java.util.List;
11  
12  import org.dom4j.Attribute;
13  import org.dom4j.CDATA;
14  import org.dom4j.Comment;
15  import org.dom4j.Document;
16  import org.dom4j.DocumentException;
17  import org.dom4j.Element;
18  import org.dom4j.Entity;
19  import org.dom4j.Namespace;
20  import org.dom4j.ProcessingInstruction;
21  import org.dom4j.Text;
22  import org.dom4j.tree.NamespaceStack;
23  
24  import org.w3c.dom.DOMImplementation;
25  
26  /***
27   * <p>
28   * <code>DOMWriter</code> takes a DOM4J tree and outputs it as a W3C DOM
29   * object
30   * </p>
31   * 
32   * @author <a href="mailto:james.strachan@metastuff.com">James Strachan </a>
33   * @version $Revision: 1.17 $
34   */
35  public class DOMWriter {
36      private static boolean loggedWarning = false;
37  
38      private static final String[] DEFAULT_DOM_DOCUMENT_CLASSES = {
39              "org.apache.xerces.dom.DocumentImpl", 
40              "gnu.xml.dom.DomDocument", 
41              "org.apache.crimson.tree.XmlDocument", 
42              "com.sun.xml.tree.XmlDocument", 
43              "oracle.xml.parser.v2.XMLDocument", 
44              "oracle.xml.parser.XMLDocument", 
45              "org.dom4j.dom.DOMDocument" 
46      };
47  
48      
49      private Class domDocumentClass;
50  
51      /*** stack of <code>Namespace</code> objects */
52      private NamespaceStack namespaceStack = new NamespaceStack();
53  
54      public DOMWriter() {
55      }
56  
57      public DOMWriter(Class domDocumentClass) {
58          this.domDocumentClass = domDocumentClass;
59      }
60  
61      public Class getDomDocumentClass() throws DocumentException {
62          Class result = domDocumentClass;
63  
64          if (result == null) {
65              
66              int size = DEFAULT_DOM_DOCUMENT_CLASSES.length;
67  
68              for (int i = 0; i < size; i++) {
69                  try {
70                      String name = DEFAULT_DOM_DOCUMENT_CLASSES[i];
71                      result = Class.forName(name, true, DOMWriter.class
72                              .getClassLoader());
73  
74                      if (result != null) {
75                          break;
76                      }
77                  } catch (Exception e) {
78                      
79                      
80                  }
81              }
82          }
83  
84          return result;
85      }
86  
87      /***
88       * Sets the DOM {@link org.w3c.dom.Document}implementation class used by
89       * the writer when creating DOM documents.
90       * 
91       * @param domDocumentClass
92       *            is the Class implementing the {@linkorg.w3c.dom.Document}
93       *            interface
94       */
95      public void setDomDocumentClass(Class domDocumentClass) {
96          this.domDocumentClass = domDocumentClass;
97      }
98  
99      /***
100      * Sets the DOM {@link org.w3c.dom.Document}implementation class name used
101      * by the writer when creating DOM documents.
102      * 
103      * @param name
104      *            is the name of the Class implementing the {@link
105      *            org.w3c.dom.Document} interface
106      * 
107      * @throws DocumentException
108      *             if the class could not be loaded
109      */
110     public void setDomDocumentClassName(String name) throws DocumentException {
111         try {
112             this.domDocumentClass = Class.forName(name, true, DOMWriter.class
113                     .getClassLoader());
114         } catch (Exception e) {
115             throw new DocumentException("Could not load the DOM Document "
116                     + "class: " + name, e);
117         }
118     }
119 
120     public org.w3c.dom.Document write(Document document)
121             throws DocumentException {
122         if (document instanceof org.w3c.dom.Document) {
123             return (org.w3c.dom.Document) document;
124         }
125 
126         resetNamespaceStack();
127 
128         org.w3c.dom.Document domDocument = createDomDocument(document);
129         appendDOMTree(domDocument, domDocument, document.content());
130         namespaceStack.clear();
131 
132         return domDocument;
133     }
134 
135     public org.w3c.dom.Document write(Document document,
136             org.w3c.dom.DOMImplementation domImpl) throws DocumentException {
137         if (document instanceof org.w3c.dom.Document) {
138             return (org.w3c.dom.Document) document;
139         }
140 
141         resetNamespaceStack();
142 
143         org.w3c.dom.Document domDocument = createDomDocument(document, domImpl);
144         appendDOMTree(domDocument, domDocument, document.content());
145         namespaceStack.clear();
146 
147         return domDocument;
148     }
149 
150     protected void appendDOMTree(org.w3c.dom.Document domDocument,
151             org.w3c.dom.Node domCurrent, List content) {
152         int size = content.size();
153 
154         for (int i = 0; i < size; i++) {
155             Object object = content.get(i);
156 
157             if (object instanceof Element) {
158                 appendDOMTree(domDocument, domCurrent, (Element) object);
159             } else if (object instanceof String) {
160                 appendDOMTree(domDocument, domCurrent, (String) object);
161             } else if (object instanceof Text) {
162                 Text text = (Text) object;
163                 appendDOMTree(domDocument, domCurrent, text.getText());
164             } else if (object instanceof CDATA) {
165                 appendDOMTree(domDocument, domCurrent, (CDATA) object);
166             } else if (object instanceof Comment) {
167                 appendDOMTree(domDocument, domCurrent, (Comment) object);
168             } else if (object instanceof Entity) {
169                 appendDOMTree(domDocument, domCurrent, (Entity) object);
170             } else if (object instanceof ProcessingInstruction) {
171                 appendDOMTree(domDocument, domCurrent,
172                         (ProcessingInstruction) object);
173             }
174         }
175     }
176 
177     protected void appendDOMTree(org.w3c.dom.Document domDocument,
178             org.w3c.dom.Node domCurrent, Element element) {
179         String elUri = element.getNamespaceURI();
180         String elName = element.getQualifiedName();
181         org.w3c.dom.Element domElement = domDocument.createElementNS(elUri,
182                 elName);
183 
184         int stackSize = namespaceStack.size();
185 
186         
187         Namespace elementNamespace = element.getNamespace();
188 
189         if (isNamespaceDeclaration(elementNamespace)) {
190             namespaceStack.push(elementNamespace);
191             writeNamespace(domElement, elementNamespace);
192         }
193 
194         
195         List declaredNamespaces = element.declaredNamespaces();
196 
197         for (int i = 0, size = declaredNamespaces.size(); i < size; i++) {
198             Namespace namespace = (Namespace) declaredNamespaces.get(i);
199 
200             if (isNamespaceDeclaration(namespace)) {
201                 namespaceStack.push(namespace);
202                 writeNamespace(domElement, namespace);
203             }
204         }
205 
206         
207         for (int i = 0, size = element.attributeCount(); i < size; i++) {
208             Attribute attribute = (Attribute) element.attribute(i);
209             String attUri = attribute.getNamespaceURI();
210             String attName = attribute.getQualifiedName();
211             String value = attribute.getValue();
212             domElement.setAttributeNS(attUri, attName, value);
213         }
214 
215         
216         appendDOMTree(domDocument, domElement, element.content());
217 
218         domCurrent.appendChild(domElement);
219 
220         while (namespaceStack.size() > stackSize) {
221             namespaceStack.pop();
222         }
223     }
224 
225     protected void appendDOMTree(org.w3c.dom.Document domDocument,
226             org.w3c.dom.Node domCurrent, CDATA cdata) {
227         org.w3c.dom.CDATASection domCDATA = domDocument
228                 .createCDATASection(cdata.getText());
229         domCurrent.appendChild(domCDATA);
230     }
231 
232     protected void appendDOMTree(org.w3c.dom.Document domDocument,
233             org.w3c.dom.Node domCurrent, Comment comment) {
234         org.w3c.dom.Comment domComment = domDocument.createComment(comment
235                 .getText());
236         domCurrent.appendChild(domComment);
237     }
238 
239     protected void appendDOMTree(org.w3c.dom.Document domDocument,
240             org.w3c.dom.Node domCurrent, String text) {
241         org.w3c.dom.Text domText = domDocument.createTextNode(text);
242         domCurrent.appendChild(domText);
243     }
244 
245     protected void appendDOMTree(org.w3c.dom.Document domDocument,
246             org.w3c.dom.Node domCurrent, Entity entity) {
247         org.w3c.dom.EntityReference domEntity = domDocument
248                 .createEntityReference(entity.getName());
249         domCurrent.appendChild(domEntity);
250     }
251 
252     protected void appendDOMTree(org.w3c.dom.Document domDoc,
253             org.w3c.dom.Node domCurrent, ProcessingInstruction pi) {
254         org.w3c.dom.ProcessingInstruction domPI = domDoc
255                 .createProcessingInstruction(pi.getTarget(), pi.getText());
256         domCurrent.appendChild(domPI);
257     }
258 
259     protected void writeNamespace(org.w3c.dom.Element domElement,
260             Namespace namespace) {
261         String attributeName = attributeNameForNamespace(namespace);
262 
263         
264         domElement.setAttribute(attributeName, namespace.getURI());
265     }
266 
267     protected String attributeNameForNamespace(Namespace namespace) {
268         String xmlns = "xmlns";
269         String prefix = namespace.getPrefix();
270 
271         if (prefix.length() > 0) {
272             return xmlns + ":" + prefix;
273         }
274 
275         return xmlns;
276     }
277 
278     protected org.w3c.dom.Document createDomDocument(Document document)
279             throws DocumentException {
280         org.w3c.dom.Document result = null;
281 
282         
283         if (domDocumentClass != null) {
284             try {
285                 result = (org.w3c.dom.Document) domDocumentClass.newInstance();
286             } catch (Exception e) {
287                 throw new DocumentException(
288                         "Could not instantiate an instance "
289                                 + "of DOM Document with class: "
290                                 + domDocumentClass.getName(), e);
291             }
292         } else {
293             
294             result = createDomDocumentViaJAXP();
295 
296             if (result == null) {
297                 Class theClass = getDomDocumentClass();
298 
299                 try {
300                     result = (org.w3c.dom.Document) theClass.newInstance();
301                 } catch (Exception e) {
302                     throw new DocumentException("Could not instantiate an "
303                             + "instance of DOM Document " + "with class: "
304                             + theClass.getName(), e);
305                 }
306             }
307         }
308 
309         return result;
310     }
311 
312     protected org.w3c.dom.Document createDomDocumentViaJAXP()
313             throws DocumentException {
314         try {
315             return JAXPHelper.createDocument(false, true);
316         } catch (Throwable e) {
317             if (!loggedWarning) {
318                 loggedWarning = true;
319 
320                 if (SAXHelper.isVerboseErrorReporting()) {
321                     
322                     
323                     System.out.println("Warning: Caught exception attempting "
324                             + "to use JAXP to create a W3C DOM " + "document");
325                     System.out.println("Warning: Exception was: " + e);
326                     e.printStackTrace();
327                 } else {
328                     System.out.println("Warning: Error occurred using JAXP to "
329                             + "create a DOM document.");
330                 }
331             }
332         }
333 
334         return null;
335     }
336 
337     protected org.w3c.dom.Document createDomDocument(Document document,
338             DOMImplementation domImpl) throws DocumentException {
339         String namespaceURI = null;
340         String qualifiedName = null;
341         org.w3c.dom.DocumentType docType = null;
342 
343         return domImpl.createDocument(namespaceURI, qualifiedName, docType);
344     }
345 
346     protected boolean isNamespaceDeclaration(Namespace ns) {
347         if ((ns != null) && (ns != Namespace.NO_NAMESPACE)
348                 && (ns != Namespace.XML_NAMESPACE)) {
349             String uri = ns.getURI();
350 
351             if ((uri != null) && (uri.length() > 0)) {
352                 if (!namespaceStack.contains(ns)) {
353                     return true;
354                 }
355             }
356         }
357 
358         return false;
359     }
360 
361     protected void resetNamespaceStack() {
362         namespaceStack.clear();
363         namespaceStack.push(Namespace.XML_NAMESPACE);
364     }
365 }
366 
367 
368 
369 
370 
371 
372 
373 
374 
375 
376 
377 
378 
379 
380 
381 
382 
383 
384 
385 
386 
387 
388 
389 
390 
391 
392 
393 
394 
395 
396 
397 
398 
399 
400 
401 
402