Docjar: A Java Source and Docuemnt Enginecom.*    java.*    javax.*    org.*    all    new    plug-in

Quick Search    Search Deep

Source code: org/jdom/output/DOMOutputter.java


1   /*-- 
2   
3    $Id: DOMOutputter.java,v 1.41 2004/09/03 06:03:42 jhunter Exp $
4   
5    Copyright (C) 2000-2004 Jason Hunter & Brett McLaughlin.
6    All rights reserved.
7    
8    Redistribution and use in source and binary forms, with or without
9    modification, are permitted provided that the following conditions
10   are met:
11   
12   1. Redistributions of source code must retain the above copyright
13      notice, this list of conditions, and the following disclaimer.
14   
15   2. Redistributions in binary form must reproduce the above copyright
16      notice, this list of conditions, and the disclaimer that follows 
17      these conditions in the documentation and/or other materials 
18      provided with the distribution.
19  
20   3. The name "JDOM" must not be used to endorse or promote products
21      derived from this software without prior written permission.  For
22      written permission, please contact <request_AT_jdom_DOT_org>.
23   
24   4. Products derived from this software may not be called "JDOM", nor
25      may "JDOM" appear in their name, without prior written permission
26      from the JDOM Project Management <request_AT_jdom_DOT_org>.
27   
28   In addition, we request (but do not require) that you include in the 
29   end-user documentation provided with the redistribution and/or in the 
30   software itself an acknowledgement equivalent to the following:
31       "This product includes software developed by the
32        JDOM Project (http://www.jdom.org/)."
33   Alternatively, the acknowledgment may be graphical using the logos 
34   available at http://www.jdom.org/images/logos.
35  
36   THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESSED OR IMPLIED
37   WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
38   OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
39   DISCLAIMED.  IN NO EVENT SHALL THE JDOM AUTHORS OR THE PROJECT
40   CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
41   SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
42   LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF
43   USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
44   ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
45   OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT
46   OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
47   SUCH DAMAGE.
48  
49   This software consists of voluntary contributions made by many 
50   individuals on behalf of the JDOM Project and was originally 
51   created by Jason Hunter <jhunter_AT_jdom_DOT_org> and
52   Brett McLaughlin <brett_AT_jdom_DOT_org>.  For more information
53   on the JDOM Project, please see <http://www.jdom.org/>.
54   
55   */
56  
57  
58  package org.jdom.output;
59  
60  import java.util.*;
61  
62  import org.jdom.*;
63  import org.jdom.adapters.*;
64  
65  
66  /**
67   * Outputs a JDOM {@link org.jdom.Document org.jdom.Document} as a DOM {@link
68   * org.w3c.dom.Document org.w3c.dom.Document}.
69   *
70   * @version $Revision: 1.41 $, $Date: 2004/09/03 06:03:42 $
71   * @author  Brett McLaughlin
72   * @author  Jason Hunter
73   * @author  Matthew Merlo
74   * @author  Dan Schaffer
75   * @author  Yusuf Goolamabbas
76   * @author  Bradley S. Huffman
77   */
78  public class DOMOutputter {
79  
80      private static final String CVS_ID = 
81        "@(#) $RCSfile: DOMOutputter.java,v $ $Revision: 1.41 $ $Date: 2004/09/03 06:03:42 $ $Name: jdom_1_0 $";
82  
83      /** Default adapter class */
84      private static final String DEFAULT_ADAPTER_CLASS =
85          "org.jdom.adapters.XercesDOMAdapter";
86  
87      /** Adapter to use for interfacing with the DOM implementation */
88      private String adapterClass;
89  
90      /**
91       * This creates a new DOMOutputter which will attempt to first locate
92       * a DOM implementation to use via JAXP, and if JAXP does not exist or
93       * there's a problem, will fall back to the default parser.
94       */
95      public DOMOutputter() {
96          // nothing
97      }
98  
99      /**
100      * This creates a new DOMOutputter using the specified DOMAdapter
101      * implementation as a way to choose the underlying parser.
102      *
103      * @param adapterClass <code>String</code> name of class
104      *                     to use for DOM output
105      */
106     public DOMOutputter(String adapterClass) {
107         this.adapterClass = adapterClass;
108     }
109 
110 
111     /**
112      * This converts the JDOM <code>Document</code> parameter to a 
113      * DOM Document, returning the DOM version.  The DOM implementation
114      * is the one chosen in the constructor.
115      *
116      * @param document <code>Document</code> to output.
117      * @return an <code>org.w3c.dom.Document</code> version
118      */
119     public org.w3c.dom.Document output(Document document)
120                                        throws JDOMException {
121         NamespaceStack namespaces = new NamespaceStack();
122 
123         org.w3c.dom.Document domDoc = null;
124         try {
125             // Assign DOCTYPE during construction
126             DocType dt = document.getDocType();
127             domDoc = createDOMDocument(dt);
128 
129             // Add content
130             Iterator itr = document.getContent().iterator();
131             while (itr.hasNext()) {
132                 Object node = itr.next();
133 
134                 if (node instanceof Element) {
135                     Element element = (Element) node;
136                     org.w3c.dom.Element domElement =
137                         output(element, domDoc, namespaces);
138                         // Add the root element, first check for existing root
139                         org.w3c.dom.Element root = domDoc.getDocumentElement();
140                         if (root == null) {
141                             // Normal case
142                             domDoc.appendChild(domElement); // normal case
143                         }
144                         else {
145                             // Xerces 1.3 creates new docs with a <root />
146                             // XXX: Need to address DOCTYPE mismatch still
147                             domDoc.replaceChild(domElement, root);
148                         }
149                 }
150                 else if (node instanceof Comment) {
151                     Comment comment = (Comment) node;
152                     org.w3c.dom.Comment domComment =
153                         domDoc.createComment(comment.getText());
154                     domDoc.appendChild(domComment);
155                 }
156                 else if (node instanceof ProcessingInstruction) {
157                     ProcessingInstruction pi = 
158                         (ProcessingInstruction) node;
159                     org.w3c.dom.ProcessingInstruction domPI =
160                          domDoc.createProcessingInstruction(
161                          pi.getTarget(), pi.getData());
162                     domDoc.appendChild(domPI);
163                 }
164                 else if (node instanceof DocType) {
165                     // We already dealt with the DocType above
166                 }
167                 else {
168                     throw new JDOMException(
169                         "Document contained top-level content with type:" +
170                         node.getClass().getName());
171                 }
172             }
173         }
174         catch (Throwable e) {
175             throw new JDOMException("Exception outputting Document", e);
176         }
177 
178         return domDoc;
179     }
180 
181     private org.w3c.dom.Document createDOMDocument(DocType dt)
182                                        throws JDOMException {
183         if (adapterClass != null) {
184             // The user knows that they want to use a particular impl
185             try {
186                 DOMAdapter adapter =
187                     (DOMAdapter)Class.forName(adapterClass).newInstance();
188                 // System.out.println("using specific " + adapterClass);
189                 return adapter.createDocument(dt);
190             }
191             catch (ClassNotFoundException e) {
192                 // e.printStackTrace();
193             }
194             catch (IllegalAccessException e) {
195                 // e.printStackTrace();
196             }
197             catch (InstantiationException e) {
198                 // e.printStackTrace();
199             }
200         }
201         else {
202             // Try using JAXP...
203             try {
204                 DOMAdapter adapter =
205                     (DOMAdapter)Class.forName(
206                     "org.jdom.adapters.JAXPDOMAdapter").newInstance();
207                 // System.out.println("using JAXP");
208                 return adapter.createDocument(dt);
209             }
210             catch (ClassNotFoundException e) {
211                 // e.printStackTrace();
212             }
213             catch (IllegalAccessException e) {
214                 // e.printStackTrace();
215             }
216             catch (InstantiationException e) {
217                 // e.printStackTrace();
218             }
219         }
220 
221         // If no DOM doc yet, try to use a hard coded default
222         try {
223             DOMAdapter adapter = (DOMAdapter)
224                 Class.forName(DEFAULT_ADAPTER_CLASS).newInstance();
225             return adapter.createDocument(dt);
226             // System.out.println("Using default " +
227             //   DEFAULT_ADAPTER_CLASS);
228         }
229         catch (ClassNotFoundException e) {
230             // e.printStackTrace();
231         }
232         catch (IllegalAccessException e) {
233             // e.printStackTrace();
234         }
235         catch (InstantiationException e) {
236             // e.printStackTrace();
237         }
238 
239         throw new JDOMException("No JAXP or default parser available");
240         
241     }
242 
243     private org.w3c.dom.Element output(Element element,
244                                          org.w3c.dom.Document domDoc,
245                                          NamespaceStack namespaces)
246                                          throws JDOMException {
247         try {
248             int previouslyDeclaredNamespaces = namespaces.size();
249 
250             org.w3c.dom.Element domElement = null;
251             if (element.getNamespace() == Namespace.NO_NAMESPACE) {
252                 // No namespace, use createElement
253                 domElement = domDoc.createElement(element.getQualifiedName());
254             }
255             else {
256                 domElement = domDoc.createElementNS(
257                                           element.getNamespaceURI(),
258                                           element.getQualifiedName());
259             }
260 
261             // Add namespace attributes, beginning with the element's own
262             // Do this only if it's not the XML namespace and it's
263             // not the NO_NAMESPACE with the prefix "" not yet mapped
264             // (we do output xmlns="" if the "" prefix was already used 
265             // and we need to reclaim it for the NO_NAMESPACE)
266             Namespace ns = element.getNamespace();
267             if (ns != Namespace.XML_NAMESPACE &&
268                            !(ns == Namespace.NO_NAMESPACE && 
269                              namespaces.getURI("") == null)) {
270                 String prefix = ns.getPrefix();
271                 String uri = namespaces.getURI(prefix);
272                 if (!ns.getURI().equals(uri)) { // output a new namespace decl
273                     namespaces.push(ns);
274                     String attrName = getXmlnsTagFor(ns);
275                     domElement.setAttribute(attrName, ns.getURI());
276                 }
277             }
278 
279             // Add additional namespaces also
280             Iterator itr = element.getAdditionalNamespaces().iterator();
281             while (itr.hasNext()) {
282                 Namespace additional = (Namespace)itr.next();
283                 String prefix = additional.getPrefix();
284                 String uri = namespaces.getURI(prefix);
285                 if (!additional.getURI().equals(uri)) {
286                     String attrName = getXmlnsTagFor(additional);
287                     domElement.setAttribute(attrName, additional.getURI());
288                     namespaces.push(additional);
289                 }
290             }
291 
292             // Add attributes to the DOM element
293             itr = element.getAttributes().iterator();
294             while (itr.hasNext()) {
295                 Attribute attribute = (Attribute) itr.next();
296                 domElement.setAttributeNode(output(attribute, domDoc));
297                 Namespace ns1 = attribute.getNamespace();
298                 if ((ns1 != Namespace.NO_NAMESPACE) && 
299                     (ns1 != Namespace.XML_NAMESPACE)) {
300                     String prefix = ns1.getPrefix();
301                     String uri = namespaces.getURI(prefix);
302                     if (!ns1.getURI().equals(uri)) { // output a new decl
303                         String attrName = getXmlnsTagFor(ns1);
304                         domElement.setAttribute(attrName, ns1.getURI());
305                         namespaces.push(ns1);
306                     }
307                 }
308                 // Crimson doesn't like setAttributeNS() for non-NS attribs
309                 if (attribute.getNamespace() == Namespace.NO_NAMESPACE) {
310                     // No namespace, use setAttribute
311                     domElement.setAttribute(attribute.getQualifiedName(),
312                                             attribute.getValue());
313                 }
314                 else {
315                     domElement.setAttributeNS(attribute.getNamespaceURI(),
316                                               attribute.getQualifiedName(),
317                                               attribute.getValue());
318                 }
319             }
320 
321             // Add content to the DOM element
322             itr = element.getContent().iterator();
323             while (itr.hasNext()) {
324                 Object node = itr.next();
325 
326                 if (node instanceof Element) {
327                     Element e = (Element) node;
328                     org.w3c.dom.Element domElt = output(e, domDoc, namespaces);
329                     domElement.appendChild(domElt);
330                 }
331                 else if (node instanceof String) {
332                     String str = (String) node;
333                     org.w3c.dom.Text domText = domDoc.createTextNode(str);
334                     domElement.appendChild(domText);
335                 }
336                 else if (node instanceof CDATA) {
337                     CDATA cdata = (CDATA) node;
338                     org.w3c.dom.CDATASection domCdata =
339                         domDoc.createCDATASection(cdata.getText());
340                     domElement.appendChild(domCdata);
341                 }
342                 else if (node instanceof Text) {
343                     Text text = (Text) node;
344                     org.w3c.dom.Text domText =
345                         domDoc.createTextNode(text.getText());
346                     domElement.appendChild(domText);
347                 }
348                 else if (node instanceof Comment) {
349                     Comment comment = (Comment) node;
350                     org.w3c.dom.Comment domComment =
351                         domDoc.createComment(comment.getText());
352                     domElement.appendChild(domComment);
353                 }
354                 else if (node instanceof ProcessingInstruction) {
355                     ProcessingInstruction pi = 
356                         (ProcessingInstruction) node;
357                     org.w3c.dom.ProcessingInstruction domPI =
358                          domDoc.createProcessingInstruction(
359                          pi.getTarget(), pi.getData());
360                     domElement.appendChild(domPI);
361                 }
362                 else if (node instanceof EntityRef) {
363                     EntityRef entity = (EntityRef) node;
364                     org.w3c.dom.EntityReference domEntity =
365                         domDoc.createEntityReference(entity.getName());
366                     domElement.appendChild(domEntity);
367                 }
368                 else {
369                     throw new JDOMException(
370                         "Element contained content with type:" +
371                         node.getClass().getName());
372                 }
373             }
374     
375             // Remove declared namespaces from stack
376             while (namespaces.size() > previouslyDeclaredNamespaces) {
377                 namespaces.pop();
378             }
379 
380             return domElement;
381         }
382         catch (Exception e) {
383             throw new JDOMException("Exception outputting Element " +
384                                     element.getQualifiedName(), e);
385         }
386     }
387 
388     private org.w3c.dom.Attr output(Attribute attribute,
389                                       org.w3c.dom.Document domDoc)
390                                       throws JDOMException {
391          org.w3c.dom.Attr domAttr = null;
392          try {
393              if (attribute.getNamespace() == Namespace.NO_NAMESPACE) {
394                  // No namespace, use createAttribute
395                  domAttr = domDoc.createAttribute(attribute.getQualifiedName());
396              }
397              else {
398                  domAttr = domDoc.createAttributeNS(attribute.getNamespaceURI(),
399                                                   attribute.getQualifiedName());
400              }
401              domAttr.setValue(attribute.getValue());
402          } catch (Exception e) {
403              throw new JDOMException("Exception outputting Attribute " +
404                                      attribute.getQualifiedName(), e);
405          }
406          return domAttr;
407     }
408 
409     /**
410      * This will handle adding any <code>{@link Namespace}</code>
411      * attributes to the DOM tree.
412      *
413      * @param ns <code>Namespace</code> to add definition of
414      */
415     private static String getXmlnsTagFor(Namespace ns) {
416         String attrName = "xmlns";
417         if (!ns.getPrefix().equals("")) {
418             attrName += ":";
419             attrName += ns.getPrefix();
420         }
421         return attrName;
422     }
423 }