001: /*
002: * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS HEADER.
003: *
004: * Copyright 1997-2007 Sun Microsystems, Inc. All rights reserved.
005: *
006: * The contents of this file are subject to the terms of either the GNU
007: * General Public License Version 2 only ("GPL") or the Common Development
008: * and Distribution License("CDDL") (collectively, the "License"). You
009: * may not use this file except in compliance with the License. You can obtain
010: * a copy of the License at https://glassfish.dev.java.net/public/CDDL+GPL.html
011: * or glassfish/bootstrap/legal/LICENSE.txt. See the License for the specific
012: * language governing permissions and limitations under the License.
013: *
014: * When distributing the software, include this License Header Notice in each
015: * file and include the License file at glassfish/bootstrap/legal/LICENSE.txt.
016: * Sun designates this particular file as subject to the "Classpath" exception
017: * as provided by Sun in the GPL Version 2 section of the License file that
018: * accompanied this code. If applicable, add the following below the License
019: * Header, with the fields enclosed by brackets [] replaced by your own
020: * identifying information: "Portions Copyrighted [year]
021: * [name of copyright owner]"
022: *
023: * Contributor(s):
024: *
025: * If you wish your version of this file to be governed by only the CDDL or
026: * only the GPL Version 2, indicate your decision by adding "[Contributor]
027: * elects to include this software in this distribution under the [CDDL or GPL
028: * Version 2] license." If you don't indicate a single choice of license, a
029: * recipient has the option to distribute your version of this file under
030: * either the CDDL, the GPL Version 2 or to extend the choice of license to
031: * its licensees as provided above. However, if you add GPL Version 2 code
032: * and therefore, elected the GPL Version 2 license, then the option applies
033: * only if the new code is made subject to such option by the copyright
034: * holder.
035: */
036:
037: package com.sun.xml.ws.util;
038:
039: import org.w3c.dom.Document;
040: import org.w3c.dom.NamedNodeMap;
041: import org.w3c.dom.Node;
042: import org.w3c.dom.NodeList;
043: import org.w3c.dom.Element;
044: import org.xml.sax.SAXException;
045:
046: import javax.xml.parsers.DocumentBuilder;
047: import javax.xml.parsers.DocumentBuilderFactory;
048: import javax.xml.parsers.FactoryConfigurationError;
049: import javax.xml.parsers.ParserConfigurationException;
050: import javax.xml.stream.XMLStreamException;
051: import javax.xml.stream.XMLStreamWriter;
052: import javax.xml.XMLConstants;
053: import javax.xml.namespace.NamespaceContext;
054: import java.io.IOException;
055: import java.io.InputStream;
056: import java.util.Iterator;
057: import java.util.List;
058: import java.util.ArrayList;
059:
060: import com.sun.istack.NotNull;
061: import com.sun.istack.Nullable;
062:
063: /**
064: * $author: JAXWS Development Team
065: */
066: public class DOMUtil {
067:
068: private static DocumentBuilder db;
069:
070: /**
071: * Creates a new DOM document.
072: */
073: public static Document createDom() {
074: synchronized (DOMUtil.class) {
075: if (db == null) {
076: try {
077: DocumentBuilderFactory dbf = DocumentBuilderFactory
078: .newInstance();
079: dbf.setNamespaceAware(true);
080: db = dbf.newDocumentBuilder();
081: } catch (ParserConfigurationException e) {
082: throw new FactoryConfigurationError(e);
083: }
084: }
085: return db.newDocument();
086: }
087: }
088:
089: public static Node createDOMNode(InputStream inputStream) {
090:
091: DocumentBuilderFactory dbf = DocumentBuilderFactory
092: .newInstance();
093: dbf.setNamespaceAware(true);
094: dbf.setValidating(false);
095: try {
096: DocumentBuilder builder = dbf.newDocumentBuilder();
097: try {
098: return builder.parse(inputStream);
099: } catch (SAXException e) {
100: e.printStackTrace(); //To change body of catch statement use File | Settings | File Templates.
101: } catch (IOException e) {
102: e.printStackTrace(); //To change body of catch statement use File | Settings | File Templates.
103: }
104: } catch (ParserConfigurationException pce) {
105: IllegalArgumentException iae = new IllegalArgumentException(
106: pce.getMessage());
107: iae.initCause(pce);
108: throw iae;
109: }
110: return null;
111: }
112:
113: /**
114: * Traverses a DOM node and writes out on a streaming writer.
115: *
116: * @param node
117: * @param writer
118: */
119: public static void serializeNode(Element node,
120: XMLStreamWriter writer) throws XMLStreamException {
121: writeTagWithAttributes(node, writer);
122:
123: if (node.hasChildNodes()) {
124: NodeList children = node.getChildNodes();
125: for (int i = 0; i < children.getLength(); i++) {
126: Node child = children.item(i);
127: switch (child.getNodeType()) {
128: case Node.PROCESSING_INSTRUCTION_NODE:
129: writer.writeProcessingInstruction(child
130: .getNodeValue());
131: case Node.DOCUMENT_TYPE_NODE:
132: break;
133: case Node.CDATA_SECTION_NODE:
134: writer.writeCData(child.getNodeValue());
135: break;
136: case Node.COMMENT_NODE:
137: writer.writeComment(child.getNodeValue());
138: break;
139: case Node.TEXT_NODE:
140: writer.writeCharacters(child.getNodeValue());
141: break;
142: case Node.ELEMENT_NODE:
143: serializeNode((Element) child, writer);
144: break;
145: }
146: }
147: }
148: writer.writeEndElement();
149: }
150:
151: public static void writeTagWithAttributes(Element node,
152: XMLStreamWriter writer) throws XMLStreamException {
153: String nodePrefix = fixNull(node.getPrefix());
154: String nodeNS = fixNull(node.getNamespaceURI());
155: //fix to work with DOM level 1 nodes.
156: String nodeLocalName = node.getLocalName() == null ? node
157: .getNodeName() : node.getLocalName();
158:
159: // See if nodePrefix:nodeNS is declared in writer's NamespaceContext before writing start element
160: // Writing start element puts nodeNS in NamespaceContext even though namespace declaration not written
161: boolean prefixDecl = isPrefixDeclared(writer, nodeNS,
162: nodePrefix);
163: writer.writeStartElement(nodePrefix, nodeLocalName, nodeNS);
164:
165: if (node.hasAttributes()) {
166: NamedNodeMap attrs = node.getAttributes();
167: int numOfAttributes = attrs.getLength();
168: // write namespace declarations first.
169: // if we interleave this with attribue writing,
170: // Zephyr will try to fix it and we end up getting inconsistent namespace bindings.
171: for (int i = 0; i < numOfAttributes; i++) {
172: Node attr = attrs.item(i);
173: String nsUri = fixNull(attr.getNamespaceURI());
174: if (nsUri.equals(XMLConstants.XMLNS_ATTRIBUTE_NS_URI)) {
175: // handle default ns declarations
176: String local = attr.getLocalName().equals(
177: XMLConstants.XMLNS_ATTRIBUTE) ? "" : attr
178: .getLocalName();
179: if (local.equals(nodePrefix)
180: && attr.getNodeValue().equals(nodeNS)) {
181: prefixDecl = true;
182: }
183: if (local.equals("")) {
184: writer.writeDefaultNamespace(attr
185: .getNodeValue());
186: } else {
187: // this is a namespace declaration, not an attribute
188: writer.setPrefix(attr.getLocalName(), attr
189: .getNodeValue());
190: writer.writeNamespace(attr.getLocalName(), attr
191: .getNodeValue());
192: }
193: }
194: }
195: }
196: // node's namespace is not declared as attribute, but declared on ancestor
197: if (!prefixDecl) {
198: writer.writeNamespace(nodePrefix, nodeNS);
199: }
200:
201: // Write all other attributes which are not namespace decl.
202: if (node.hasAttributes()) {
203: NamedNodeMap attrs = node.getAttributes();
204: int numOfAttributes = attrs.getLength();
205:
206: for (int i = 0; i < numOfAttributes; i++) {
207: Node attr = attrs.item(i);
208: String attrPrefix = fixNull(attr.getPrefix());
209: String attrNS = fixNull(attr.getNamespaceURI());
210: if (!attrNS.equals(XMLConstants.XMLNS_ATTRIBUTE_NS_URI)) {
211: String localName = attr.getLocalName();
212: if (localName == null) {
213: // TODO: this is really a bug in the caller for not creating proper DOM tree.
214: // will remove this workaround after plugfest
215: localName = attr.getNodeName();
216: }
217: boolean attrPrefixDecl = isPrefixDeclared(writer,
218: attrNS, attrPrefix);
219: if (!attrPrefix.equals("") && !attrPrefixDecl) {
220: // attr has namespace but namespace decl is there in ancestor node
221: // So write the namespace decl before writing the attr
222: writer.setPrefix(attr.getLocalName(), attr
223: .getNodeValue());
224: writer.writeNamespace(attrPrefix, attrNS);
225: }
226: writer.writeAttribute(attrPrefix, attrNS,
227: localName, attr.getNodeValue());
228: }
229: }
230: }
231: }
232:
233: private static boolean isPrefixDeclared(XMLStreamWriter writer,
234: String nsUri, String prefix) {
235: boolean prefixDecl = false;
236: NamespaceContext nscontext = writer.getNamespaceContext();
237: Iterator prefixItr = nscontext.getPrefixes(nsUri);
238: while (prefixItr.hasNext()) {
239: if (prefix.equals(prefixItr.next())) {
240: prefixDecl = true;
241: break;
242: }
243: }
244: return prefixDecl;
245: }
246:
247: /**
248: * Gets the first child of the given name, or null.
249: */
250: public static Element getFirstChild(Element e, String nsUri,
251: String local) {
252: for (Node n = e.getFirstChild(); n != null; n = n
253: .getNextSibling()) {
254: if (n.getNodeType() == Node.ELEMENT_NODE) {
255: Element c = (Element) n;
256: if (c.getLocalName().equals(local)
257: && c.getNamespaceURI().equals(nsUri))
258: return c;
259: }
260: }
261: return null;
262: }
263:
264: private static @NotNull
265: String fixNull(@Nullable
266: String s) {
267: if (s == null)
268: return "";
269: else
270: return s;
271: }
272:
273: /**
274: * Gets the first element child.
275: */
276: public static @Nullable
277: Element getFirstElementChild(Node parent) {
278: for (Node n = parent.getFirstChild(); n != null; n = n
279: .getNextSibling()) {
280: if (n.getNodeType() == Node.ELEMENT_NODE) {
281: return (Element) n;
282: }
283: }
284: return null;
285: }
286:
287: public static @NotNull
288: List<Element> getChildElements(Node parent) {
289: List<Element> elements = new ArrayList<Element>();
290: for (Node n = parent.getFirstChild(); n != null; n = n
291: .getNextSibling()) {
292: if (n.getNodeType() == Node.ELEMENT_NODE) {
293: elements.add((Element) n);
294: }
295: }
296: return elements;
297: }
298: }
|