offline building of site deploy to improve performance.
[utils] / support / general / src / main / java / org / wamblee / xml / DomUtils.java
1 /*
2  * Copyright 2005-2010 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 package org.wamblee.xml;
17
18 import java.io.ByteArrayInputStream;
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 import java.util.logging.Level;
28 import java.util.logging.Logger;
29
30 import javax.xml.XMLConstants;
31 import javax.xml.parsers.DocumentBuilder;
32 import javax.xml.parsers.DocumentBuilderFactory;
33 import javax.xml.parsers.ParserConfigurationException;
34 import javax.xml.transform.Transformer;
35 import javax.xml.transform.TransformerException;
36 import javax.xml.transform.TransformerFactory;
37 import javax.xml.transform.dom.DOMSource;
38 import javax.xml.transform.stream.StreamResult;
39 import javax.xml.transform.stream.StreamSource;
40 import javax.xml.validation.Schema;
41 import javax.xml.validation.SchemaFactory;
42 import javax.xml.validation.Validator;
43
44 import org.w3c.dom.Attr;
45 import org.w3c.dom.Document;
46 import org.w3c.dom.Element;
47 import org.w3c.dom.NamedNodeMap;
48 import org.w3c.dom.Node;
49 import org.w3c.dom.NodeList;
50 import org.w3c.dom.bootstrap.DOMImplementationRegistry;
51 import org.w3c.dom.ls.DOMImplementationLS;
52 import org.w3c.dom.ls.LSException;
53 import org.w3c.dom.ls.LSInput;
54 import org.w3c.dom.ls.LSParser;
55 import org.xml.sax.SAXException;
56
57 /**
58  * Some basic XML utilities for common reoccuring tasks for DOM documents.
59  * 
60  * @author Erik Brakkee
61  */
62 public final class DomUtils {
63     private static final Logger LOG = Logger
64         .getLogger(DomUtils.class.getName());
65
66     /**
67      * Disabled default constructor.
68      * 
69      */
70     private DomUtils() {
71         // Empty.
72     }
73
74     /**
75      * Gets a dom level 3 implementation. 
76      * @return Dom implementation.
77      * @throws ClassNotFoundException
78      * @throws InstantiationException
79      * @throws IllegalAccessException
80      */
81     public static DOMImplementationLS getDomImplementationLS() {
82         final String message = "Could not get Dom level 3 implementation";
83         try {
84             DOMImplementationRegistry registry = DOMImplementationRegistry
85                 .newInstance();
86
87             DOMImplementationLS impl = (DOMImplementationLS) registry
88                 .getDOMImplementation("LS");
89             return impl;
90         } catch (ClassCastException e) {
91             throw new RuntimeException(message, e);
92         } catch (ClassNotFoundException e) {
93             throw new RuntimeException(message, e);
94         } catch (InstantiationException e) {
95             throw new RuntimeException(message, e);
96         } catch (IllegalAccessException e) {
97             throw new RuntimeException(message, e);
98         }
99     }
100
101     /**
102      * Removes duplicate attributes from a DOM tree.This is useful for
103      * postprocessing the output of JTidy as a workaround for a bug in JTidy.
104      * 
105      * @param aNode
106      *            Node to remove duplicate attributes from (recursively).
107      *            Attributes of the node itself are not dealt with. Only the
108      *            child nodes are dealt with.
109      */
110     public static void removeDuplicateAttributes(Node aNode) {
111         NodeList list = aNode.getChildNodes();
112
113         for (int i = 0; i < list.getLength(); i++) {
114             Node node = list.item(i);
115
116             if (node instanceof Element) {
117                 removeDuplicateAttributes((Element) node);
118                 removeDuplicateAttributes(node);
119             }
120         }
121     }
122
123     /**
124      * Removes duplicate attributes from an element.
125      * 
126      * @param aElement
127      *            Element.
128      */
129     private static void removeDuplicateAttributes(Element aElement) {
130         NamedNodeMap attributes = aElement.getAttributes();
131         Map<String, Attr> uniqueAttributes = new TreeMap<String, Attr>();
132         List<Attr> attlist = new ArrayList<Attr>();
133
134         for (int i = 0; i < attributes.getLength(); i++) {
135             Attr attribute = (Attr) attributes.item(i);
136
137             if (uniqueAttributes.containsKey(attribute.getNodeName())) {
138                 LOG.info("Detected duplicate attribute (will be removed)'" +
139                     attribute.getNodeName() + "'");
140             }
141
142             uniqueAttributes.put(attribute.getNodeName(), attribute);
143             attlist.add(attribute);
144         }
145
146         // Remove all attributes from the element.
147         for (Attr att : attlist) {
148             aElement.removeAttributeNode(att);
149         }
150
151         // Add the unique attributes back to the element.
152         for (Attr att : uniqueAttributes.values()) {
153             aElement.setAttributeNode(att);
154         }
155     }
156 }