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.soap.util;
018    
019    import java.io.IOException;
020    import java.io.InputStream;
021    
022    import javax.xml.XMLConstants;
023    import javax.xml.namespace.QName;
024    import javax.xml.parsers.DocumentBuilderFactory;
025    import javax.xml.parsers.ParserConfigurationException;
026    import javax.xml.transform.Source;
027    import javax.xml.transform.Transformer;
028    import javax.xml.transform.TransformerConfigurationException;
029    import javax.xml.transform.TransformerException;
030    import javax.xml.transform.TransformerFactory;
031    import javax.xml.transform.dom.DOMResult;
032    
033    import org.apache.servicemix.soap.api.Fault;
034    import org.w3c.dom.Document;
035    import org.w3c.dom.Element;
036    import org.w3c.dom.Node;
037    import org.w3c.dom.NodeList;
038    import org.xml.sax.SAXException;
039    
040    /**
041     * DOM related utilities.
042     * 
043     * @author <a href="mailto:gnodet [at] gmail.com">Guillaume Nodet</a>
044     */
045    public class DomUtil {
046    
047        private static DocumentBuilderFactory documentBuilderFactory;
048        private static TransformerFactory transformerFactory;
049        
050        public static Document createDocument() {
051            try {
052                return getDocumentBuilderFactory().newDocumentBuilder().newDocument();
053            } catch (ParserConfigurationException e) {
054                throw new Fault(e);
055            }
056        }
057        
058        public static Document parse(InputStream is) {
059            try {
060                return getDocumentBuilderFactory().newDocumentBuilder().parse(is);
061            } catch (SAXException e) {
062                throw new Fault(e);
063            } catch (IOException e) {
064                throw new Fault(e);
065            } catch (ParserConfigurationException e) {
066                throw new Fault(e);
067            }
068        }
069        
070        public static Document parse(Source source) {
071            try {
072                Document doc = createDocument();
073                DOMResult result = new DOMResult(doc);
074                Transformer transformer = getTransformerFactory().newTransformer();
075                transformer.transform(source, result);
076                return doc;
077            } catch (TransformerConfigurationException e) {
078                throw new Fault(e);
079            } catch (TransformerException e) {
080                throw new Fault(e);
081            }
082        }
083    
084        public static DocumentBuilderFactory getDocumentBuilderFactory() {
085            if (documentBuilderFactory == null) {
086                DocumentBuilderFactory f = DocumentBuilderFactory.newInstance();
087                f.setNamespaceAware(true);
088                documentBuilderFactory = f;
089            }
090            return documentBuilderFactory;
091        }
092        
093        public static TransformerFactory getTransformerFactory() {
094            if (transformerFactory == null) {
095                transformerFactory =  TransformerFactory.newInstance();
096            }
097            return transformerFactory;
098        }
099    
100        /**
101         * Get the first child element
102         * @param parent
103         * @return
104         */
105        public static Element getFirstChildElement(Node parent) {
106            NodeList childs = parent.getChildNodes();
107            for (int i = 0; i < childs.getLength(); i++) {
108                Node child = childs.item(i);
109                if (child instanceof Element) {
110                    return (Element) child;
111                }
112            }
113            return null;
114        }
115        
116        /**
117         * Returns the text of the element
118         */
119        public static String getElementText(Element element) {
120            StringBuffer buffer = new StringBuffer();
121            NodeList nodeList = element.getChildNodes();
122            for (int i = 0, size = nodeList.getLength(); i < size; i++) {
123                Node node = nodeList.item(i);
124                if (node.getNodeType() == Node.TEXT_NODE || node.getNodeType() == Node.CDATA_SECTION_NODE) {
125                    buffer.append(node.getNodeValue());
126                }
127            }
128            return buffer.toString();
129        }
130    
131        /**
132         * Get the next sibling element
133         * @param el
134         * @return
135         */
136        public static Element getNextSiblingElement(Element el) {
137            for (Node n = el.getNextSibling(); n != null; n = n.getNextSibling()) {
138                if (n instanceof Element) {
139                    return (Element) n;
140                }
141            }
142            return null;
143        }
144        
145        public static Element createElement(Node parent, QName name) {
146            Document doc = parent instanceof Document ? (Document) parent : parent.getOwnerDocument();
147            Element element;
148            if (name.getPrefix() != null && name.getPrefix().length() > 0) {
149                element = doc.createElementNS(name.getNamespaceURI(), name.getPrefix() + ":" + name.getLocalPart());
150                String attr = recursiveGetAttributeValue(parent, XMLConstants.XMLNS_ATTRIBUTE + ":" + name.getPrefix());
151                if (attr == null || !attr.equals(name.getNamespaceURI())) {
152                    element.setAttribute(XMLConstants.XMLNS_ATTRIBUTE + ":" + name.getPrefix(), 
153                                         name.getNamespaceURI());
154                }
155            } else if (name.getNamespaceURI() != null && name.getNamespaceURI().length() > 0) {
156                element = doc.createElementNS(name.getNamespaceURI(), name.getLocalPart());
157                String attr = recursiveGetAttributeValue(parent, XMLConstants.XMLNS_ATTRIBUTE);
158                if (attr == null || !attr.equals(name.getNamespaceURI())) {
159                    element.setAttribute(XMLConstants.XMLNS_ATTRIBUTE, 
160                                         name.getNamespaceURI());
161                }
162            } else {
163                element = doc.createElementNS(null, name.getLocalPart());
164                String attr = recursiveGetAttributeValue(parent, XMLConstants.XMLNS_ATTRIBUTE);
165                if (attr == null || attr.length() > 0) {
166                    element.setAttribute(XMLConstants.XMLNS_ATTRIBUTE, 
167                                         "");
168                }
169            }
170            parent.appendChild(element);
171            return element;
172        }
173        
174        /**
175         * Creates a QName instance from the given namespace context for the given qualifiedName
176         *
177         * @param element       the element to use as the namespace context
178         * @param qualifiedName the fully qualified name
179         * @return the QName which matches the qualifiedName
180         */
181        public static QName createQName(Element element, String qualifiedName) {
182            int index = qualifiedName.indexOf(':');
183            if (index >= 0) {
184                String prefix = qualifiedName.substring(0, index);
185                String localName = qualifiedName.substring(index + 1);
186                String uri = recursiveGetAttributeValue(element, XMLConstants.XMLNS_ATTRIBUTE + ":" + prefix);
187                return new QName(uri, localName, prefix);
188            }
189            else {
190                String uri = recursiveGetAttributeValue(element, XMLConstants.XMLNS_ATTRIBUTE);
191                if (uri != null) {
192                    return new QName(uri, qualifiedName);
193                }
194                return new QName(qualifiedName);
195            }
196        }
197    
198        /**
199         * Recursive method to find a given attribute value
200         */
201        public static String recursiveGetAttributeValue(Node parent, String attributeName) {
202            if (parent instanceof Element) {
203                Element element = (Element) parent;
204                String answer = element.getAttribute(attributeName);
205                if (answer == null || answer.length() == 0) {
206                    Node parentNode = element.getParentNode();
207                    if (parentNode instanceof Element) {
208                        return recursiveGetAttributeValue((Element) parentNode, attributeName);
209                    }
210                }
211                return answer;
212            } else {
213                return null;
214            }
215        }
216    
217        protected static String getUniquePrefix(Element element) {
218            int n = 1;
219            while (true) {
220                String nsPrefix = "ns" + n;
221                if (recursiveGetAttributeValue(element, XMLConstants.XMLNS_ATTRIBUTE + ":" + nsPrefix) == null) {
222                    return nsPrefix;
223                }
224                n++;
225            }
226        }
227    
228        public static QName getQName(Element el) {
229            if (el == null) {
230                return null;
231            } else if (el.getPrefix() != null) {
232                return new QName(el.getNamespaceURI(), el.getLocalName(), el.getPrefix());
233            } else {
234                return new QName(el.getNamespaceURI(), el.getLocalName());
235            }
236        }
237    
238    }