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 }