(no commit message)
[utils] / support / src / org / wamblee / xml / DomUtils.java
1 /*
2  * Copyright 2005 the original author or authors.
3  * 
4  * Licensed under the Apache License, Version 2.0 (the "License");
5  * you may not use this file except in compliance with the License.
6  * You may obtain a copy of the License at
7  * 
8  *      http://www.apache.org/licenses/LICENSE-2.0
9  * 
10  * Unless required by applicable law or agreed to in writing, software
11  * distributed under the License is distributed on an "AS IS" BASIS,
12  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13  * See the License for the specific language governing permissions and
14  * limitations under the License.
15  */ 
16
17 package org.wamblee.xml;
18
19 import java.io.ByteArrayOutputStream;
20 import java.io.IOException;
21 import java.io.InputStream;
22 import java.io.OutputStream;
23 import java.util.ArrayList;
24 import java.util.List;
25 import java.util.Map;
26 import java.util.TreeMap;
27
28 import javax.xml.parsers.DocumentBuilder;
29 import javax.xml.parsers.DocumentBuilderFactory;
30 import javax.xml.parsers.ParserConfigurationException;
31
32 import org.apache.xml.serialize.OutputFormat;
33 import org.apache.xml.serialize.XMLSerializer;
34 import org.dom4j.DocumentException;
35 import org.dom4j.io.DOMReader;
36 import org.dom4j.io.DOMWriter;
37 import org.w3c.dom.Attr;
38 import org.w3c.dom.Document;
39 import org.w3c.dom.Element;
40 import org.w3c.dom.NamedNodeMap;
41 import org.w3c.dom.Node;
42 import org.w3c.dom.NodeList;
43 import org.xml.sax.SAXException;
44
45 /**
46  * Some basic XML utilities for common reoccuring tasks for 
47  * DOM documents.  
48  */
49 public final class DomUtils {
50     
51     /**
52      * Disabled default constructor. 
53      *
54      */
55     private DomUtils() { 
56         // Empty. 
57     }
58     
59     
60     /**
61      * Parses an XML document from a stream. 
62      * @param aIs Input stream. 
63      * @return
64      */
65     public static Document read(InputStream aIs) throws SAXException, ParserConfigurationException, IOException { 
66         DocumentBuilder builder = DocumentBuilderFactory.newInstance().newDocumentBuilder(); 
67         return builder.parse(aIs);     
68     }
69
70     /**
71      * Serializes an XML document to a stream. 
72      * @param aDocument Document to serialize. 
73      * @param aOs Output stream. 
74      */
75     public static void serialize(Document aDocument, OutputStream aOs) throws IOException { 
76         XMLSerializer serializer = new XMLSerializer(aOs, new OutputFormat());
77         serializer.serialize(aDocument);
78     }
79     
80     /**
81      * Serializes an XML document. 
82      * @param aDocument Document to serialize. 
83      * @return Serialized document. 
84      */
85     public static String serialize(Document aDocument) throws IOException {
86         ByteArrayOutputStream os = new ByteArrayOutputStream();
87         serialize(aDocument, os); 
88         return os.toString(); 
89     }
90     
91     /**
92      * Converts a dom4j document into a w3c DOM document. 
93      * @param aDocument Document to convert. 
94      * @return W3C DOM document. 
95      */
96     public static Document convert(org.dom4j.Document aDocument) throws DocumentException {
97         return new DOMWriter().write(aDocument);
98     }
99
100     /**
101      * Converts a W3C DOM document into a dom4j document. 
102      * @param aDocument Document to convert. 
103      * @return Dom4j document.
104      */
105     public static org.dom4j.Document convert(Document aDocument) { 
106         return new DOMReader().read(aDocument); 
107     }
108     
109     /**
110      * Removes duplicate attributes from a DOM tree.This is useful for postprocessing the
111      * output of JTidy as a workaround for a bug in JTidy. 
112      * 
113      * @param aNode
114      *            Node to remove duplicate attributes from (recursively).
115      *            Attributes of the node itself are not dealt with. Only the
116      *            child nodes are dealt with.
117      */
118     public static void removeDuplicateAttributes(Node aNode) {
119         NodeList list = aNode.getChildNodes();
120         for (int i = 0; i < list.getLength(); i++) {
121             Node node = list.item(i);
122             if (node instanceof Element) {
123                 removeDuplicateAttributes((Element) node);
124                 removeDuplicateAttributes(node);
125             }
126         }
127     }
128
129     /**
130      * Removes duplicate attributes from an element.
131      * 
132      * @param aElement
133      *            Element.
134      */
135     private static void removeDuplicateAttributes(Element aElement) {
136         NamedNodeMap attributes = aElement.getAttributes();
137         Map<String, Attr> uniqueAttributes = new TreeMap<String, Attr>();
138         List<Attr> attlist = new ArrayList<Attr>();
139         for (int i = 0; i < attributes.getLength(); i++) {
140             Attr attribute = (Attr) attributes.item(i);
141             if (uniqueAttributes.containsKey(attribute.getNodeName())) {
142                 System.out.println("Detected duplicate attribute '"
143                         + attribute.getNodeName() + "'");
144             }
145             uniqueAttributes.put(attribute.getNodeName(), attribute);
146             attlist.add(attribute);
147         }
148         // Remove all attributes from the element.
149         for (Attr att : attlist) {
150             aElement.removeAttributeNode(att);
151         }
152         // Add the unique attributes back to the element.
153         for (Attr att : uniqueAttributes.values()) {
154             aElement.setAttributeNode(att);
155         }
156     }
157 }