/*
* Copyright (c) 2009, IETR/INSA of Rennes
* Copyright (c) 2012, Synflow
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions are met:
*
* * Redistributions of source code must retain the above copyright notice,
* this list of conditions and the following disclaimer.
* * Redistributions in binary form must reproduce the above copyright notice,
* this list of conditions and the following disclaimer in the documentation
* and/or other materials provided with the distribution.
* * Neither the name of the IETR/INSA of Rennes nor the names of its
* contributors may be used to endorse or promote products derived from this
* software without specific prior written permission.
*
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
* AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
* ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE
* LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
* CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
* SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
* INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT,
* STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY
* WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
* SUCH DAMAGE.
*/
package net.sf.orcc.util;
import java.io.ByteArrayInputStream;
import java.io.ByteArrayOutputStream;
import java.io.InputStream;
import java.io.OutputStream;
import net.sf.orcc.OrccRuntimeException;
import org.w3c.dom.DOMConfiguration;
import org.w3c.dom.DOMImplementation;
import org.w3c.dom.Document;
import org.w3c.dom.Element;
import org.w3c.dom.NamedNodeMap;
import org.w3c.dom.Node;
import org.w3c.dom.NodeList;
import org.w3c.dom.bootstrap.DOMImplementationRegistry;
import org.w3c.dom.ls.DOMImplementationLS;
import org.w3c.dom.ls.LSInput;
import org.w3c.dom.ls.LSOutput;
import org.w3c.dom.ls.LSParser;
import org.w3c.dom.ls.LSSerializer;
/**
* This class defines utility methods to create DOM documents, to print them to
* an output stream using DOM 3 Load Save objects and to make easier the parsing
* of XML files.
*
* @author Matthieu Wipliez
* @author Herve Yviquel
*
*/
public class DomUtil {
private static DOMImplementation impl;
private static DOMImplementationRegistry registry;
/**
* Creates a new DOM document.
*
* @param docElt
* name of the document element
* @return a new DOM document
*/
public static Document createDocument(String docElt) {
getImplementation();
return impl.createDocument("", docElt, null);
}
/**
* @param root
* @return
*/
public static Element getFirstElementChild(Node root) {
Node node = root.getFirstChild();
while (node != null) {
if (node.getNodeType() == Node.ELEMENT_NODE) {
return (Element) node;
}
node = node.getNextSibling();
}
return null;
}
/**
* Creates a new instance of the DOM registry and get an implementation of
* DOM 3 with Load Save objects.
*/
private static void getImplementation() {
try {
if (registry == null) {
registry = DOMImplementationRegistry.newInstance();
}
if (impl == null) {
impl = registry.getDOMImplementation("Core 3.0 XML 3.0 LS");
if (impl == null) {
throw new OrccRuntimeException(
"no DOM 3 implementation found");
}
}
} catch (ClassNotFoundException e) {
throw new OrccRuntimeException("DOM error", e);
} catch (InstantiationException e) {
throw new OrccRuntimeException("DOM error", e);
} catch (IllegalAccessException e) {
throw new OrccRuntimeException("DOM error", e);
}
}
/**
* Returns the next sibling element of the given node.
*
* @param node
* the given node
* @return the next sibling element of the given node
*/
public static Element getNextElementSibling(Node node) {
node = node.getNextSibling();
while (node != null) {
if (node.getNodeType() == Node.ELEMENT_NODE) {
return (Element) node;
}
node = node.getNextSibling();
}
return null;
}
public static Node getNode(String tagName, NodeList nodes) {
for (int x = 0; x < nodes.getLength(); x++) {
Node node = nodes.item(x);
if (node.getNodeName().equalsIgnoreCase(tagName)) {
return node;
}
}
return null;
}
/**
* Returns the value of the attribute for the given node.
*
* @param attrName
* the name of the attribute
* @param node
* the given node
*
* @return the value of the attribute for the given node
*/
public static String getNodeAttr(String attrName, Node node) {
NamedNodeMap attrs = node.getAttributes();
for (int y = 0; y < attrs.getLength(); y++) {
Node attr = attrs.item(y);
if (attr.getNodeName().equalsIgnoreCase(attrName)) {
return attr.getNodeValue();
}
}
return "";
}
/**
* Returns the value of the attribute for the given node.
*
* @param attrName
* the name of the attribute
* @param node
* the given node
*
* @return the value of the attribute for the given node
*/
public static int getNodeIntAttr(String attrName, Node node) {
return Integer.parseInt(getNodeAttr(attrName, node));
}
/**
* Return the integer value of the given node.
*
* @param node
* a node
* @return the integer value of the given node
*/
public static int getNodeIntValue(Node node) throws NumberFormatException {
return Integer.parseInt(getNodeValue(node));
}
/**
* Return the integer value of the node identified by the given tag from the
* given list of nodes.
*
* @param tagName
* a tag
* @param nodes
* a list of nodes
* @return the integer value of the node identified by the given tag from
* the given list of nodes
*/
public static int getChildIntValue(String tagName, Node node)
throws NumberFormatException {
return Integer.parseInt(getChildValue(tagName, node));
}
/**
* Return the string value of the given node (eventually empty).
*
* @param node
* a node
* @return the string value of the given node
*/
public static String getNodeValue(Node node) {
NodeList childNodes = node.getChildNodes();
for (int x = 0; x < childNodes.getLength(); x++) {
Node data = childNodes.item(x);
if (data.getNodeType() == Node.TEXT_NODE)
return data.getNodeValue();
}
return "";
}
/**
* Return the string value (eventually empty) of the node identified with
* the given tag from the given list of nodes.
*
* @param tagName
* a tag identifying the node
* @param node
* a list of nodes
* @return the string value of the node identified with the given tag from
* the given list of nodes
*/
public static String getChildValue(String tagName, Node node) {
Element child = getFirstElementChild(node);
while (child != null) {
if (child.getNodeName().equals(tagName)) {
return getNodeValue(child);
}
child = getNextElementSibling(child);
}
return "";
}
/**
* Parses the given input stream as XML and returns the corresponding DOM
* document.
*
* @param is
* an input stream
* @return a DOM document
*/
public static Document parseDocument(InputStream is) {
getImplementation();
DOMImplementationLS implLS = (DOMImplementationLS) impl;
// create input
LSInput input = implLS.createLSInput();
input.setByteStream(is);
// parse without comments and whitespace
LSParser builder = implLS.createLSParser(
DOMImplementationLS.MODE_SYNCHRONOUS, null);
DOMConfiguration config = builder.getDomConfig();
config.setParameter("comments", false);
config.setParameter("element-content-whitespace", false);
return builder.parse(input);
}
/**
* Parses the given String as XML and returns the corresponding DOM
* document. The String is converted to an input stream so that encoding is
* taken into account (otherwise if we pass a String to an LSInput DOM will
* ignore the encoding and assume UTF-16).
*
* @param str
* a String
* @return a DOM document
*/
public static Document parseDocument(String str) {
return parseDocument(new ByteArrayInputStream(str.getBytes()));
}
/**
* Writes the given node to the given output stream.
*
* @param os
* an output stream
* @param node
* a DOM node
*/
public static void writeDocument(OutputStream os, Node node) {
getImplementation();
DOMImplementationLS implLS = (DOMImplementationLS) impl;
// serialize to XML
LSOutput output = implLS.createLSOutput();
output.setByteStream(os);
// serialize the document, close the stream
LSSerializer serializer = implLS.createLSSerializer();
serializer.getDomConfig().setParameter("format-pretty-print", true);
serializer.write(node, output);
}
/**
* Returns a string representation of the given node. Like
* {@link #parseDocument(String)}, we use an intermediary byte array output
* stream so we can specify the encoding.
*
* @param node
* a DOM node
*/
public static String writeToString(Node node) {
ByteArrayOutputStream os = new ByteArrayOutputStream();
writeDocument(os, node);
return os.toString();
}
}