/**
* Copyright (c) 2011, SOCIETIES Consortium (WATERFORD INSTITUTE OF TECHNOLOGY (TSSG), HERIOT-WATT UNIVERSITY (HWU), SOLUTA.NET
* (SN), GERMAN AEROSPACE CENTRE (Deutsches Zentrum fuer Luft- und Raumfahrt e.V.) (DLR), Zavod za varnostne tehnologije
* informacijske družbe in elektronsko poslovanje (SETCCE), INSTITUTE OF COMMUNICATION AND COMPUTER SYSTEMS (ICCS), LAKE
* COMMUNICATIONS (LAKE), INTEL PERFORMANCE LEARNING SOLUTIONS LTD (INTEL), PORTUGAL TELECOM INOVAÇÃO, SA (PTIN), IBM Corp.,
* INSTITUT TELECOM (ITSUD), AMITEC DIACHYTI EFYIA PLIROFORIKI KAI EPIKINONIES ETERIA PERIORISMENIS EFTHINIS (AMITEC), TELECOM
* ITALIA S.p.a.(TI), TRIALOG (TRIALOG), Stiftelsen SINTEF (SINTEF), NEC EUROPE LTD (NEC))
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without modification, are permitted provided that the following
* conditions are met:
*
* 1. Redistributions of source code must retain the above copyright notice, this list of conditions and the following disclaimer.
*
* 2. 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.
*
* 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 HOLDER 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 org.societies.security.policynegotiator.xml;
import java.io.StringReader;
import java.io.StringWriter;
import javax.xml.parsers.DocumentBuilder;
import javax.xml.parsers.DocumentBuilderFactory;
import javax.xml.transform.Result;
import javax.xml.transform.Source;
import javax.xml.transform.Transformer;
import javax.xml.transform.TransformerConfigurationException;
import javax.xml.transform.TransformerException;
import javax.xml.transform.TransformerFactory;
import javax.xml.transform.dom.DOMSource;
import javax.xml.transform.stream.StreamResult;
import javax.xml.xpath.XPath;
import javax.xml.xpath.XPathConstants;
import javax.xml.xpath.XPathExpression;
import javax.xml.xpath.XPathExpressionException;
import javax.xml.xpath.XPathFactory;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.w3c.dom.DOMException;
import org.w3c.dom.Document;
import org.w3c.dom.NamedNodeMap;
import org.w3c.dom.Node;
import org.w3c.dom.NodeList;
import org.xml.sax.InputSource;
/**
* Generic XML support
*
* @author Mitja Vardjan
*/
public class Xml {
private static Logger Log = LoggerFactory.getLogger(Xml.class);
private Document doc;
private XPath xpathObj;
public Xml(String source) throws XmlException {
DocumentBuilderFactory dbf = DocumentBuilderFactory.newInstance();
DocumentBuilder db;
try {
db = dbf.newDocumentBuilder();
doc = db.parse(new InputSource(new StringReader(source)));
} catch (Exception ex) {
throw new XmlException(ex);
}
doc.getDocumentElement().normalize();
xpathObj = XPathFactory.newInstance().newXPath();
}
public Xml(Document doc) throws XmlException {
this.doc = doc;
doc.getDocumentElement().normalize();
xpathObj = XPathFactory.newInstance().newXPath();
}
/**
* Get XML node given with XPath and parse its text contents to get double
*
* @param xpath
* The XPath expression
* @return The value in text contents of the node or -1 if the text contents
* could not be parsed.
*/
/*
* public double getDouble(String xpath) { String value; double num;
*
* value = getValue(xpath); try { num = Double.parseDouble(value); } catch
* (NumberFormatException ex) { return -1; } catch (NullPointerException ex)
* { return -1; }
*
* return num; }
*/
public String getValue(String xpath) {
NodeList nodes;
String value;
nodes = getNodes(xpath);
if (nodes.getLength() == 0) {
return null;
} else if (nodes.getLength() > 1) {
Log.warn("getValue(" + xpath + "Found more than 1 XML node");
}
value = nodes.item(0).getTextContent();
return value;
}
/**
* Finds XML nodes with given XPath expression.
*
* @param xpath
* The XPath expression
* @return List of matching nodes or null on error
*/
public NodeList getNodes(String xpath) {
XPathExpression expr;
Object result;
try {
expr = xpathObj.compile(xpath);
result = expr.evaluate(doc, XPathConstants.NODESET);
} catch (XPathExpressionException ex) {
Log.warn("getNodes(" + xpath + ")", ex);
return null;
}
return (NodeList) result;
}
/**
* Create new child node and add it to parent node even if the new node
* already exists.
*
* @param parent
* the node to append new node to
* @param newNode
* Name of the new node. Can be XPath expression and all needed
* nodes will be generated.
* @return new node
*/
public Node addNode(Node parent, String newNode) {
Node child;
String[] name;
Document ownerDoc = getOwnerDocument(parent);
if (newNode.startsWith("/")) {
newNode = newNode.substring(1);
}
name = newNode.split("[/]");
for (int i = 0; i < name.length; i++) {
try {
child = ownerDoc.createElement(name[i]);
} catch (DOMException ex) {
Log.debug("addNode(): Node name: \"" + name[i] + "\"", ex);
return null;
}
parent.appendChild(child);
parent = child;
}
return parent;
}
/**
* Remove given XML nodes.
*
* @param xpath
* XPath expression
*/
public void removeNodes(String xpath) {
NodeList nodes = getNodes(xpath);
if (nodes != null) {
for (int k = 0; k < nodes.getLength(); k++) {
doc.removeChild(nodes.item(k));
}
}
}
@Override
public String toString() {
try {
Source source = new DOMSource(doc);
StringWriter stringWriter = new StringWriter();
Result result = new StreamResult(stringWriter);
TransformerFactory factory = TransformerFactory.newInstance();
Transformer transformer = factory.newTransformer();
transformer.transform(source, result);
return stringWriter.getBuffer().toString();
} catch (TransformerConfigurationException ex) {
Log.error("toString(): " + ex.getMessage(), ex);
} catch (TransformerException ex) {
Log.error("toString(): " + ex.getMessage(), ex);
}
return null;
}
/**
*
* @param xpath
* @return Contents of given node
*/
public String toString(String xpath) {
Node node;
NodeList nodes = getNodes(xpath);
if (nodes == null) {
Log.error("toString(" + xpath + "): No nodes found");
return null;
}
Log.debug("toString(" + xpath + "): " + nodes.getLength() + " nodes found");
if (nodes == null || nodes.getLength() != 1) {
Log.warn("toString(" + xpath + "): Number of nodes not 1, but " + nodes.getLength());
return null;
}
node = nodes.item(0);
try {
Source source = new DOMSource(node);
StringWriter stringWriter = new StringWriter();
Result result = new StreamResult(stringWriter);
TransformerFactory factory = TransformerFactory.newInstance();
Transformer transformer = factory.newTransformer();
transformer.transform(source, result);
String s = stringWriter.getBuffer().toString();
Log.debug("toString(): " + s);
return s;
} catch (TransformerConfigurationException ex) {
Log.error("toString(): " + ex.getMessage(), ex);
} catch (TransformerException ex) {
Log.error("toString(): " + ex.getMessage(), ex);
}
return null;
}
/**
*
* @param xpath
* @return Contents of given node
*/
public String toPrettyString(String xpath) {
Node node;
NodeList nodes = getNodes(xpath);
if (nodes == null) {
Log.error("toString(" + xpath + "): No nodes found");
return null;
}
Log.debug("toString(" + xpath + "): " + nodes.getLength() + " nodes found");
if (nodes == null || nodes.getLength() != 1) {
Log.warn("toString(" + xpath + "): Number of nodes not 1, but " + nodes.getLength());
return null;
}
node = nodes.item(0);
return textRepresentation(node, false);
}
private String textRepresentation(Node node, boolean includeRootNode) {
StringBuffer buf = new StringBuffer();
NamedNodeMap attributes;
String textContent;
NodeList childNodes;
Log.debug("textRepresentation(" + node.getNodeName() + ", " + includeRootNode + ")");
if (includeRootNode) {
buf.append(node.getNodeName());
attributes = node.getAttributes();
if (attributes != null && attributes.getLength() > 0) {
for (int k = 0; k < attributes.getLength(); k++) {
buf.append(" " + attributes.item(k).getNodeName() + "=" + attributes.item(k).getNodeValue());
}
}
}
childNodes = node.getChildNodes();
if (childNodes != null && childNodes.getLength() > 0) {
for (int k = 0; k < childNodes.getLength(); k++) {
buf.append(textRepresentation(childNodes.item(k), true));
}
}
else {
textContent = node.getTextContent();
if (textContent != null && textContent.length() > 0) {
buf.append(textContent);
}
}
Log.debug("textRepresentation(" +
node.getNodeName() + ", " + includeRootNode + "): " + buf.toString());
return buf.toString();
}
/**
* Create new child node and add it to parent node if the new node does not
* already exist.
*
* @param parent
* the node to append new node to
* @param newNode
* Name of the new node. Can have slashes (like XPath) and any
* missing nodes will also be created.
* @return new node
*/
public static Node addNodeIfNotPresent(Node parent, String newNode) {
Node child;
String[] name;
if (newNode.startsWith("/")) {
newNode = newNode.substring(1);
}
name = newNode.split("[/]");
for (int i = 0; i < name.length; i++) {
child = getFirstNode(parent, name[i]);
if (child == null) {
child = getOwnerDocument(parent).createElement(name[i]);
parent.appendChild(child);
}
parent = child;
}
return parent;
}
/**
* From the given XML node get XML nodes that satisfy XPath expression. Only
* the inner XML part of that node is searched, not the whole XML.
*
* @param node
* @param xpath
* XPath expression
* @return List of nodes that satisfy given XPath expression
*/
public static NodeList getNodes(Node node, String xpath) {
NodeList nodes = null;
XPathExpression expr;
Object result;
try {
expr = XPathFactory.newInstance().newXPath().compile(xpath);
result = expr.evaluate(node, XPathConstants.NODESET);
nodes = (NodeList) result;
} catch (XPathExpressionException ex) {
}
return nodes;
}
/**
* Calls getNodes() and returns the first node
*
* @param node
* @param xpath
* @return the first node found with getNodes()
*/
public static Node getFirstNode(Node node, String xpath) {
NodeList nodes;
nodes = getNodes(node, xpath);
if (nodes == null || nodes.getLength() == 0) {
return null;
}
return nodes.item(0);
}
/**
* Get owner document for the given node. If the given node is itself
* Document, the casted node is returned.
*
* @param node
* @return Owner document
*/
private static Document getOwnerDocument(Node node) {
Document ownerDoc;
ownerDoc = node.getOwnerDocument();
if (ownerDoc == null) {
ownerDoc = (Document) node;
}
return ownerDoc;
}
public String getAttributeValue(String xpathToNode, String attribName) {
Node node;
NamedNodeMap attribs;
NodeList nodes = this.getNodes(xpathToNode);
Log.debug("getAttribute(" + xpathToNode + ", "
+ attribName + "): " + nodes.getLength() + " nodes found");
if (nodes.getLength() < 1) {
return null;
}
for (int k = 0; k < nodes.getLength(); k++) {
node = nodes.item(k);
attribs = node.getAttributes();
for (int l = 0; l < attribs.getLength(); l++) {
Log.debug("getAttribute(" + xpathToNode
+ ", " + attribName + "): Attribute no. " + l);
if (attribs.item(l).getNodeName().equals(attribName)) {
Log.debug("getAttribute(" + xpathToNode
+ ", " + attribName + "): " + "Found attribute "
+ attribName + "=" + attribs.item(l).getNodeValue());
return attribs.item(l).getNodeValue();
}
}
}
return null;
}
public static String getAttribute(Node node, String name) {
NamedNodeMap attributes = node.getAttributes();
if (attributes == null) {
return null;
}
Node attrib = attributes.getNamedItem(name);
if (attrib == null) {
return null;
}
return attrib.getNodeValue();
}
}