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