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