001    /*
002     * Licensed to the Apache Software Foundation (ASF) under one or more
003     * contributor license agreements.  See the NOTICE file distributed with
004     * this work for additional information regarding copyright ownership.
005     * The ASF licenses this file to You under the Apache License, Version 2.0
006     * (the "License"); you may not use this file except in compliance with
007     * the License.  You may obtain a copy of the License at
008     *
009     *      http://www.apache.org/licenses/LICENSE-2.0
010     *
011     * Unless required by applicable law or agreed to in writing, software
012     * distributed under the License is distributed on an "AS IS" BASIS,
013     * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
014     * See the License for the specific language governing permissions and
015     * limitations under the License.
016     */
017    package org.apache.servicemix.jbi.util;
018    
019    import java.io.StringWriter;
020    import java.util.Queue;
021    import java.util.concurrent.ConcurrentLinkedQueue;
022    
023    import javax.xml.namespace.QName;
024    import javax.xml.parsers.DocumentBuilder;
025    import javax.xml.parsers.DocumentBuilderFactory;
026    import javax.xml.parsers.ParserConfigurationException;
027    import javax.xml.transform.OutputKeys;
028    import javax.xml.transform.Transformer;
029    import javax.xml.transform.TransformerException;
030    import javax.xml.transform.TransformerFactory;
031    import javax.xml.transform.dom.DOMSource;
032    import javax.xml.transform.stream.StreamResult;
033    
034    import org.w3c.dom.Attr;
035    import org.w3c.dom.Document;
036    import org.w3c.dom.Element;
037    import org.w3c.dom.NamedNodeMap;
038    import org.w3c.dom.Node;
039    import org.w3c.dom.NodeList;
040    
041    import org.apache.commons.logging.Log;
042    import org.apache.commons.logging.LogFactory;
043    
044    /**
045     * A collection of W3C DOM helper methods
046     *
047     * @version $Revision: 564607 $
048     */
049    public final class DOMUtil {
050        
051        private static final Log LOG = LogFactory.getLog(DOMUtil.class);
052        private static DocumentBuilderFactory dbf;
053        private static Queue builders = new ConcurrentLinkedQueue();
054    
055        
056        private DOMUtil() {
057        }
058    
059        /**
060         * Returns the text of the element
061         */
062        public static String getElementText(Element element) {
063            StringBuffer buffer = new StringBuffer();
064            NodeList nodeList = element.getChildNodes();
065            for (int i = 0; i < nodeList.getLength(); i++) {
066                Node node = nodeList.item(i);
067                if (node.getNodeType() == Node.TEXT_NODE || node.getNodeType() == Node.CDATA_SECTION_NODE) {
068                    buffer.append(node.getNodeValue());
069                }
070            }
071            return buffer.toString();
072        }
073    
074        /**
075         * Moves the content of the given element to the given element
076         */
077        public static void moveContent(Element from, Element to) {
078            // lets move the child nodes across
079            NodeList childNodes = from.getChildNodes();
080            while (childNodes.getLength() > 0) {
081                Node node = childNodes.item(0);
082                from.removeChild(node);
083                to.appendChild(node);
084            }
085        }
086    
087        /**
088         * Copy the attribues on one element to the other
089         */
090        public static void copyAttributes(Element from, Element to) {
091            // lets copy across all the remainingattributes
092            NamedNodeMap attributes = from.getAttributes();
093            for (int i = 0; i < attributes.getLength(); i++) {
094                Attr node = (Attr) attributes.item(i);
095                to.setAttributeNS(node.getNamespaceURI(), node.getName(), node.getValue());
096            }
097        }
098    
099        /**
100         * A helper method useful for debugging and logging which will convert the given DOM node into XML text
101         */
102        public static String asXML(Node node) throws TransformerException {
103            Transformer transformer = TransformerFactory.newInstance().newTransformer();
104            StringWriter buffer = new StringWriter();
105            transformer.transform(new DOMSource(node), new StreamResult(buffer));
106            return buffer.toString();
107        }
108    
109        /**
110         * A helper method useful for debugging and logging which will convert the given DOM node into XML text
111         */
112        public static String asIndentedXML(Node node) throws TransformerException {
113            Transformer transformer = TransformerFactory.newInstance().newTransformer();
114            transformer.setOutputProperty(OutputKeys.INDENT, "yes");
115            StringWriter buffer = new StringWriter();
116            transformer.transform(new DOMSource(node), new StreamResult(buffer));
117            return buffer.toString();
118        }
119    
120        /**
121         * Adds the child element with the given text
122         */
123        public static void addChildElement(Element element, String name, Object textValue) {
124            Document document = element.getOwnerDocument();
125            Element child = document.createElement(name);
126            element.appendChild(child);
127            if (textValue != null) {
128                String text = textValue.toString();
129                child.appendChild(document.createTextNode(text));
130            }
131        }
132    
133        /**
134         * Creates a QName instance from the given namespace context for the given qualifiedName
135         *
136         * @param element       the element to use as the namespace context
137         * @param qualifiedName the fully qualified name
138         * @return the QName which matches the qualifiedName
139         */
140        public static QName createQName(Element element, String qualifiedName) {
141            int index = qualifiedName.indexOf(':');
142            if (index >= 0) {
143                String prefix = qualifiedName.substring(0, index);
144                String localName = qualifiedName.substring(index + 1);
145                String uri = recursiveGetAttributeValue(element, "xmlns:" + prefix);
146                return new QName(uri, localName, prefix);
147            } else {
148                String uri = recursiveGetAttributeValue(element, "xmlns");
149                if (uri != null) {
150                    return new QName(uri, qualifiedName);
151                }
152                return new QName(qualifiedName);
153            }
154        }
155    
156        /**
157         * Recursive method to find a given attribute value
158         */
159        public static String recursiveGetAttributeValue(Element element, String attributeName) {
160            String answer = null;
161            try {
162                answer = element.getAttribute(attributeName);
163            } catch (Exception e) {
164                if (LOG.isTraceEnabled()) {
165                    LOG.trace("Caught exception looking up attribute: " + attributeName + " on element: " + element + ". Cause: " + e, e);
166                }
167            }
168            if (answer == null || answer.length() == 0) {
169                Node parentNode = element.getParentNode();
170                if (parentNode instanceof Element) {
171                    return recursiveGetAttributeValue((Element) parentNode, attributeName);
172                }
173            }
174            return answer;
175        }
176    
177        /**
178         * Get the first child element
179         * @param parent
180         * @return
181         */
182        public static Element getFirstChildElement(Node parent) {
183            NodeList childs = parent.getChildNodes();
184            for (int i = 0; i < childs.getLength(); i++) {
185                Node child = childs.item(i);
186                if (child instanceof Element) {
187                    return (Element) child;
188                }
189            }
190            return null;
191        }
192        
193        /**
194         * Get the next sibling element
195         * @param el
196         * @return
197         */
198        public static Element getNextSiblingElement(Element el) {
199            for (Node n = el.getNextSibling(); n != null; n = n.getNextSibling()) {
200                if (n instanceof Element) {
201                    return (Element) n;
202                }
203            }
204            return null;
205        }
206        
207        /**
208         * Build a QName from the element name
209         * @param el
210         * @return
211         */
212        public static QName getQName(Element el) {
213            if (el == null) {
214                return null;
215            } else if (el.getPrefix() != null) {
216                return new QName(el.getNamespaceURI(), el.getLocalName(), el.getPrefix());
217            } else {
218                return new QName(el.getNamespaceURI(), el.getLocalName());
219            }
220        }
221    
222        public static DocumentBuilder getBuilder() throws ParserConfigurationException {
223            DocumentBuilder builder = (DocumentBuilder) builders.poll();
224            if (builder == null) {
225                if (dbf == null) {
226                    dbf = DocumentBuilderFactory.newInstance();
227                    dbf.setNamespaceAware(true);
228                }
229                builder = dbf.newDocumentBuilder();
230            }
231            return builder;
232        }
233    
234        public static void releaseBuilder(DocumentBuilder builder) {
235            builders.add(builder);
236        }
237    
238        /**
239         * Return a new document, ready to populate.
240         * @return
241         * @throws ParserConfigurationException
242         */
243        public static Document newDocument() throws ParserConfigurationException {
244            DocumentBuilder builder = getBuilder();
245            Document doc = builder.newDocument();
246            releaseBuilder(builder);
247            return doc;
248        }
249    
250    }