aoqi@0: /* aoqi@0: * Copyright (c) 1997, 2013, Oracle and/or its affiliates. All rights reserved. aoqi@0: * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. aoqi@0: * aoqi@0: * This code is free software; you can redistribute it and/or modify it aoqi@0: * under the terms of the GNU General Public License version 2 only, as aoqi@0: * published by the Free Software Foundation. Oracle designates this aoqi@0: * particular file as subject to the "Classpath" exception as provided aoqi@0: * by Oracle in the LICENSE file that accompanied this code. aoqi@0: * aoqi@0: * This code is distributed in the hope that it will be useful, but WITHOUT aoqi@0: * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or aoqi@0: * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License aoqi@0: * version 2 for more details (a copy is included in the LICENSE file that aoqi@0: * accompanied this code). aoqi@0: * aoqi@0: * You should have received a copy of the GNU General Public License version aoqi@0: * 2 along with this work; if not, write to the Free Software Foundation, aoqi@0: * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. aoqi@0: * aoqi@0: * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA aoqi@0: * or visit www.oracle.com if you need additional information or have any aoqi@0: * questions. aoqi@0: */ aoqi@0: aoqi@0: package com.sun.xml.internal.ws.util; aoqi@0: aoqi@0: import com.sun.istack.internal.NotNull; aoqi@0: import com.sun.istack.internal.Nullable; aoqi@0: import com.sun.xml.internal.ws.util.xml.XmlUtil; aoqi@0: import org.w3c.dom.*; aoqi@0: aoqi@0: import javax.xml.XMLConstants; aoqi@0: import javax.xml.namespace.NamespaceContext; aoqi@0: import javax.xml.parsers.DocumentBuilder; aoqi@0: import javax.xml.parsers.DocumentBuilderFactory; aoqi@0: import javax.xml.parsers.FactoryConfigurationError; aoqi@0: import javax.xml.parsers.ParserConfigurationException; aoqi@0: import javax.xml.stream.XMLStreamException; aoqi@0: import javax.xml.stream.XMLStreamWriter; aoqi@0: import java.util.ArrayList; aoqi@0: import java.util.Iterator; aoqi@0: import java.util.List; aoqi@0: aoqi@0: /** aoqi@0: * @author JAXWS Development Team aoqi@0: */ aoqi@0: public class DOMUtil { aoqi@0: aoqi@0: private static DocumentBuilder db; aoqi@0: aoqi@0: /** aoqi@0: * Creates a new DOM document. aoqi@0: */ aoqi@0: public static Document createDom() { aoqi@0: synchronized (DOMUtil.class) { aoqi@0: if (db == null) { aoqi@0: try { aoqi@0: DocumentBuilderFactory dbf = XmlUtil.newDocumentBuilderFactory(); aoqi@0: dbf.setNamespaceAware(true); aoqi@0: db = dbf.newDocumentBuilder(); aoqi@0: } catch (ParserConfigurationException e) { aoqi@0: throw new FactoryConfigurationError(e); aoqi@0: } aoqi@0: } aoqi@0: return db.newDocument(); aoqi@0: } aoqi@0: } aoqi@0: aoqi@0: /** aoqi@0: * Traverses a DOM node and writes out on a streaming writer. aoqi@0: * aoqi@0: * @param node aoqi@0: * @param writer aoqi@0: */ aoqi@0: public static void serializeNode(Element node, XMLStreamWriter writer) throws XMLStreamException { aoqi@0: writeTagWithAttributes(node, writer); aoqi@0: aoqi@0: if (node.hasChildNodes()) { aoqi@0: NodeList children = node.getChildNodes(); aoqi@0: for (int i = 0; i < children.getLength(); i++) { aoqi@0: Node child = children.item(i); aoqi@0: switch (child.getNodeType()) { aoqi@0: case Node.PROCESSING_INSTRUCTION_NODE: aoqi@0: writer.writeProcessingInstruction(child.getNodeValue()); aoqi@0: break; aoqi@0: case Node.DOCUMENT_TYPE_NODE: aoqi@0: break; aoqi@0: case Node.CDATA_SECTION_NODE: aoqi@0: writer.writeCData(child.getNodeValue()); aoqi@0: break; aoqi@0: case Node.COMMENT_NODE: aoqi@0: writer.writeComment(child.getNodeValue()); aoqi@0: break; aoqi@0: case Node.TEXT_NODE: aoqi@0: writer.writeCharacters(child.getNodeValue()); aoqi@0: break; aoqi@0: case Node.ELEMENT_NODE: aoqi@0: serializeNode((Element) child, writer); aoqi@0: break; aoqi@0: default: break; aoqi@0: } aoqi@0: } aoqi@0: } aoqi@0: writer.writeEndElement(); aoqi@0: } aoqi@0: aoqi@0: public static void writeTagWithAttributes(Element node, XMLStreamWriter writer) throws XMLStreamException { aoqi@0: String nodePrefix = fixNull(node.getPrefix()); aoqi@0: String nodeNS = fixNull(node.getNamespaceURI()); aoqi@0: //fix to work with DOM level 1 nodes. aoqi@0: String nodeLocalName = node.getLocalName()== null?node.getNodeName():node.getLocalName(); aoqi@0: aoqi@0: // See if nodePrefix:nodeNS is declared in writer's NamespaceContext before writing start element aoqi@0: // Writing start element puts nodeNS in NamespaceContext even though namespace declaration not written aoqi@0: boolean prefixDecl = isPrefixDeclared(writer, nodeNS, nodePrefix); aoqi@0: writer.writeStartElement(nodePrefix, nodeLocalName, nodeNS); aoqi@0: aoqi@0: if (node.hasAttributes()) { aoqi@0: NamedNodeMap attrs = node.getAttributes(); aoqi@0: int numOfAttributes = attrs.getLength(); aoqi@0: // write namespace declarations first. aoqi@0: // if we interleave this with attribue writing, aoqi@0: // Zephyr will try to fix it and we end up getting inconsistent namespace bindings. aoqi@0: for (int i = 0; i < numOfAttributes; i++) { aoqi@0: Node attr = attrs.item(i); aoqi@0: String nsUri = fixNull(attr.getNamespaceURI()); aoqi@0: if (nsUri.equals(XMLConstants.XMLNS_ATTRIBUTE_NS_URI)) { aoqi@0: // handle default ns declarations aoqi@0: String local = attr.getLocalName().equals(XMLConstants.XMLNS_ATTRIBUTE) ? "" : attr.getLocalName(); aoqi@0: if (local.equals(nodePrefix) && attr.getNodeValue().equals(nodeNS)) { aoqi@0: prefixDecl = true; aoqi@0: } aoqi@0: if (local.equals("")) { aoqi@0: writer.writeDefaultNamespace(attr.getNodeValue()); aoqi@0: } else { aoqi@0: // this is a namespace declaration, not an attribute aoqi@0: writer.setPrefix(attr.getLocalName(), attr.getNodeValue()); aoqi@0: writer.writeNamespace(attr.getLocalName(), attr.getNodeValue()); aoqi@0: } aoqi@0: } aoqi@0: } aoqi@0: } aoqi@0: // node's namespace is not declared as attribute, but declared on ancestor aoqi@0: if (!prefixDecl) { aoqi@0: writer.writeNamespace(nodePrefix, nodeNS); aoqi@0: } aoqi@0: aoqi@0: // Write all other attributes which are not namespace decl. aoqi@0: if (node.hasAttributes()) { aoqi@0: NamedNodeMap attrs = node.getAttributes(); aoqi@0: int numOfAttributes = attrs.getLength(); aoqi@0: aoqi@0: for (int i = 0; i < numOfAttributes; i++) { aoqi@0: Node attr = attrs.item(i); aoqi@0: String attrPrefix = fixNull(attr.getPrefix()); aoqi@0: String attrNS = fixNull(attr.getNamespaceURI()); aoqi@0: if (!attrNS.equals(XMLConstants.XMLNS_ATTRIBUTE_NS_URI)) { aoqi@0: String localName = attr.getLocalName(); aoqi@0: if (localName == null) { aoqi@0: // TODO: this is really a bug in the caller for not creating proper DOM tree. aoqi@0: // will remove this workaround after plugfest aoqi@0: localName = attr.getNodeName(); aoqi@0: } aoqi@0: boolean attrPrefixDecl = isPrefixDeclared(writer, attrNS, attrPrefix); aoqi@0: if (!attrPrefix.equals("") && !attrPrefixDecl) { aoqi@0: // attr has namespace but namespace decl is there in ancestor node aoqi@0: // So write the namespace decl before writing the attr aoqi@0: writer.setPrefix(attr.getLocalName(), attr.getNodeValue()); aoqi@0: writer.writeNamespace(attrPrefix, attrNS); aoqi@0: } aoqi@0: writer.writeAttribute(attrPrefix, attrNS, localName, attr.getNodeValue()); aoqi@0: } aoqi@0: } aoqi@0: } aoqi@0: } aoqi@0: aoqi@0: private static boolean isPrefixDeclared(XMLStreamWriter writer, String nsUri, String prefix) { aoqi@0: boolean prefixDecl = false; aoqi@0: NamespaceContext nscontext = writer.getNamespaceContext(); aoqi@0: Iterator prefixItr = nscontext.getPrefixes(nsUri); aoqi@0: while (prefixItr.hasNext()) { aoqi@0: if (prefix.equals(prefixItr.next())) { aoqi@0: prefixDecl = true; aoqi@0: break; aoqi@0: } aoqi@0: } aoqi@0: return prefixDecl; aoqi@0: } aoqi@0: aoqi@0: /** aoqi@0: * Gets the first child of the given name, or null. aoqi@0: */ aoqi@0: public static Element getFirstChild(Element e, String nsUri, String local) { aoqi@0: for (Node n = e.getFirstChild(); n != null; n = n.getNextSibling()) { aoqi@0: if (n.getNodeType() == Node.ELEMENT_NODE) { aoqi@0: Element c = (Element) n; aoqi@0: if (c.getLocalName().equals(local) && c.getNamespaceURI().equals(nsUri)) { aoqi@0: return c; aoqi@0: } aoqi@0: } aoqi@0: } aoqi@0: return null; aoqi@0: } aoqi@0: aoqi@0: private static aoqi@0: @NotNull aoqi@0: String fixNull(@Nullable String s) { aoqi@0: if (s == null) { aoqi@0: return ""; aoqi@0: } else { aoqi@0: return s; aoqi@0: } aoqi@0: } aoqi@0: aoqi@0: /** aoqi@0: * Gets the first element child. aoqi@0: */ aoqi@0: public static aoqi@0: @Nullable aoqi@0: Element getFirstElementChild(Node parent) { aoqi@0: for (Node n = parent.getFirstChild(); n != null; n = n.getNextSibling()) { aoqi@0: if (n.getNodeType() == Node.ELEMENT_NODE) { aoqi@0: return (Element) n; aoqi@0: } aoqi@0: } aoqi@0: return null; aoqi@0: } aoqi@0: aoqi@0: public static @NotNull aoqi@0: List getChildElements(Node parent){ aoqi@0: List elements = new ArrayList(); aoqi@0: for (Node n = parent.getFirstChild(); n != null; n = n.getNextSibling()) { aoqi@0: if (n.getNodeType() == Node.ELEMENT_NODE) { aoqi@0: elements.add((Element)n); aoqi@0: } aoqi@0: } aoqi@0: return elements; aoqi@0: } aoqi@0: }