1 /* 2 * Copyright (c) 2014, Oracle and/or its affiliates. All rights reserved. 3 * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. 4 * 5 * This code is free software; you can redistribute it and/or modify it 6 * under the terms of the GNU General Public License version 2 only, as 7 * published by the Free Software Foundation. 8 * 9 * This code is distributed in the hope that it will be useful, but WITHOUT 10 * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or 11 * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License 12 * version 2 for more details (a copy is included in the LICENSE file that 13 * accompanied this code). 14 * 15 * You should have received a copy of the GNU General Public License version 16 * 2 along with this work; if not, write to the Free Software Foundation, 17 * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. 18 * 19 * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA 20 * or visit www.oracle.com if you need additional information or have any 21 * questions. 22 */ 23 24 package stream.XMLStreamWriterTest; 25 26 import java.io.IOException; 27 import java.io.InputStream; 28 import java.util.Iterator; 29 30 import javax.xml.XMLConstants; 31 import javax.xml.namespace.NamespaceContext; 32 import javax.xml.parsers.DocumentBuilder; 33 import javax.xml.parsers.DocumentBuilderFactory; 34 import javax.xml.parsers.FactoryConfigurationError; 35 import javax.xml.parsers.ParserConfigurationException; 36 import javax.xml.stream.XMLStreamException; 37 import javax.xml.stream.XMLStreamWriter; 38 39 import org.w3c.dom.Document; 40 import org.w3c.dom.Element; 41 import org.w3c.dom.NamedNodeMap; 42 import org.w3c.dom.Node; 43 import org.w3c.dom.NodeList; 44 import org.xml.sax.SAXException; 45 46 public class DOMUtil { 47 48 private static DocumentBuilder db; 49 50 private static String fixNull(String s) { 51 if (s == null) 52 return ""; 53 else 54 return s; 55 } 56 57 /** 58 * Creates a new DOM document. 59 */ 60 public static Document createDom() { 61 synchronized (DOMUtil.class) { 62 if (db == null) { 63 try { 64 DocumentBuilderFactory dbf = DocumentBuilderFactory.newInstance(); 65 dbf.setNamespaceAware(true); 66 db = dbf.newDocumentBuilder(); 67 } catch (ParserConfigurationException e) { 68 throw new FactoryConfigurationError(e); 69 } 70 } 71 return db.newDocument(); 72 } 73 } 74 75 public static Node createDOMNode(InputStream inputStream) { 76 77 DocumentBuilderFactory dbf = DocumentBuilderFactory.newInstance(); 78 dbf.setNamespaceAware(true); 79 dbf.setValidating(false); 80 try { 81 DocumentBuilder builder = dbf.newDocumentBuilder(); 82 try { 83 return builder.parse(inputStream); 84 } catch (SAXException e) { 85 e.printStackTrace(); // To change body of catch statement use 86 // File | Settings | File Templates. 87 } catch (IOException e) { 88 e.printStackTrace(); // To change body of catch statement use 89 // File | Settings | File Templates. 90 } 91 } catch (ParserConfigurationException pce) { 92 IllegalArgumentException iae = new IllegalArgumentException(pce.getMessage()); 93 iae.initCause(pce); 94 throw iae; 95 } 96 return null; 97 } 98 99 public static void serializeNode(Element node, XMLStreamWriter writer) throws XMLStreamException { 100 String nodePrefix = fixNull(node.getPrefix()); 101 String nodeNS = fixNull(node.getNamespaceURI()); 102 103 // See if nodePrefix:nodeNS is declared in writer's NamespaceContext 104 // before writing start element 105 // Writing start element puts nodeNS in NamespaceContext even though 106 // namespace declaration not written 107 boolean prefixDecl = isPrefixDeclared(writer, nodeNS, nodePrefix); 108 109 writer.writeStartElement(nodePrefix, node.getLocalName(), nodeNS); 110 111 if (node.hasAttributes()) { 112 NamedNodeMap attrs = node.getAttributes(); 113 int numOfAttributes = attrs.getLength(); 114 // write namespace declarations first. 115 // if we interleave this with attribue writing, 116 // Zephyr will try to fix it and we end up getting inconsistent 117 // namespace bindings. 118 for (int i = 0; i < numOfAttributes; i++) { 119 Node attr = attrs.item(i); 120 String nsUri = fixNull(attr.getNamespaceURI()); 121 if (nsUri.equals(XMLConstants.XMLNS_ATTRIBUTE_NS_URI)) { 122 // handle default ns declarations 123 String local = attr.getLocalName().equals(XMLConstants.XMLNS_ATTRIBUTE) ? "" : attr.getLocalName(); 124 if (local.equals(nodePrefix) && attr.getNodeValue().equals(nodeNS)) { 125 prefixDecl = true; 126 } 127 // this is a namespace declaration, not an attribute 128 writer.setPrefix(attr.getLocalName(), attr.getNodeValue()); 129 writer.writeNamespace(attr.getLocalName(), attr.getNodeValue()); 130 } 131 } 132 } 133 // node's namespace is not declared as attribute, but declared on 134 // ancestor 135 if (!prefixDecl) { 136 writer.writeNamespace(nodePrefix, nodeNS); 137 } 138 139 // Write all other attributes which are not namespace decl. 140 if (node.hasAttributes()) { 141 NamedNodeMap attrs = node.getAttributes(); 142 int numOfAttributes = attrs.getLength(); 143 144 for (int i = 0; i < numOfAttributes; i++) { 145 Node attr = attrs.item(i); 146 String attrPrefix = fixNull(attr.getPrefix()); 147 String attrNS = fixNull(attr.getNamespaceURI()); 148 if (!attrNS.equals(XMLConstants.XMLNS_ATTRIBUTE_NS_URI)) { 149 String localName = attr.getLocalName(); 150 if (localName == null) { 151 // TODO: this is really a bug in the caller for not 152 // creating proper DOM tree. 153 // will remove this workaround after plugfest 154 localName = attr.getNodeName(); 155 } 156 boolean attrPrefixDecl = isPrefixDeclared(writer, attrNS, attrPrefix); 157 if (!attrPrefix.equals("") && !attrPrefixDecl) { 158 // attr has namespace but namespace decl is there in 159 // ancestor node 160 // So write the namespace decl before writing the attr 161 writer.setPrefix(attr.getLocalName(), attr.getNodeValue()); 162 writer.writeNamespace(attrPrefix, attrNS); 163 } 164 writer.writeAttribute(attrPrefix, attrNS, localName, attr.getNodeValue()); 165 } 166 } 167 } 168 169 if (node.hasChildNodes()) { 170 NodeList children = node.getChildNodes(); 171 for (int i = 0; i < children.getLength(); i++) { 172 Node child = children.item(i); 173 switch (child.getNodeType()) { 174 case Node.PROCESSING_INSTRUCTION_NODE: 175 writer.writeProcessingInstruction(child.getNodeValue()); 176 case Node.DOCUMENT_TYPE_NODE: 177 break; 178 case Node.CDATA_SECTION_NODE: 179 writer.writeCData(child.getNodeValue()); 180 break; 181 case Node.COMMENT_NODE: 182 writer.writeComment(child.getNodeValue()); 183 break; 184 case Node.TEXT_NODE: 185 writer.writeCharacters(child.getNodeValue()); 186 break; 187 case Node.ELEMENT_NODE: 188 serializeNode((Element) child, writer); 189 break; 190 } 191 } 192 } 193 writer.writeEndElement(); 194 } 195 196 private static boolean isPrefixDeclared(XMLStreamWriter writer, String nsUri, String prefix) { 197 boolean prefixDecl = false; 198 NamespaceContext nscontext = writer.getNamespaceContext(); 199 Iterator prefixItr = nscontext.getPrefixes(nsUri); 200 while (prefixItr.hasNext()) { 201 if (prefix.equals(prefixItr.next())) { 202 prefixDecl = true; 203 break; 204 } 205 } 206 return prefixDecl; 207 } 208 209 /** 210 * Gets the first child of the given name, or null. 211 */ 212 public static Element getFirstChild(Element e, String nsUri, String local) { 213 for (Node n = e.getFirstChild(); n != null; n = n.getNextSibling()) { 214 if (n.getNodeType() == Node.ELEMENT_NODE) { 215 Element c = (Element) n; 216 if (c.getLocalName().equals(local) && c.getNamespaceURI().equals(nsUri)) 217 return c; 218 } 219 } 220 return null; 221 } 222 223 }