/**
* 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.digsig.util;
import java.io.ByteArrayInputStream;
import java.io.ByteArrayOutputStream;
import java.io.File;
import java.io.FileInputStream;
import java.io.FileNotFoundException;
import java.io.FileOutputStream;
import java.io.IOException;
import java.io.InputStream;
import java.io.OutputStream;
import java.io.OutputStreamWriter;
import java.io.StringReader;
import java.io.StringWriter;
import java.io.UnsupportedEncodingException;
import java.util.HashMap;
import java.util.Map;
import javax.xml.parsers.DocumentBuilder;
import javax.xml.parsers.DocumentBuilderFactory;
import javax.xml.transform.Result;
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.w3c.dom.Document;
import org.w3c.dom.Element;
import org.w3c.dom.Node;
import org.w3c.dom.NodeList;
import org.xml.sax.InputSource;
/**
* @author Miroslav Pavleski, Mitja Vardjan
*/
public class XmlManipulator {
private DocumentBuilderFactory factory;
private DocumentBuilder builder;
private XPath xpath;
private Map<String, XPathExpression> expCache;
private Document doc;
private DOMSource docSource;
private Transformer transformer;
public void setDocument(Document inDoc) {
doc = inDoc;
expCache = new HashMap<String, XPathExpression>();
if (xpath == null) {
XPathFactory xpathFactory = XPathFactory.newInstance();
xpath = xpathFactory.newXPath();
}
docSource = new DOMSource(doc);
}
public void load(InputStream fis) {
doc = null;
try {
if (factory == null) {
factory = DocumentBuilderFactory.newInstance();
factory.setNamespaceAware(true);
builder = factory.newDocumentBuilder();
expCache = new HashMap<String, XPathExpression>();
}
if (xpath == null) {
XPathFactory xpathFactory = XPathFactory.newInstance();
xpath = xpathFactory.newXPath();
}
doc = builder.parse(fis);
docSource = new DOMSource(doc);
} catch (Exception e) {
throw new RuntimeException("Failed to parse XML.", e);
}
}
public void load(String xmlStr) {
try {
load(new ByteArrayInputStream(xmlStr.getBytes("utf-8")));
} catch (UnsupportedEncodingException e) {
// should not happen
}
}
public void load(File file) {
FileInputStream fis = null;
try {
fis = new FileInputStream(file);
} catch (FileNotFoundException e) {
throw new RuntimeException("Failed to load file!", e);
} finally {
if (fis != null)
try {
fis.close();
} catch (IOException e) {
}
}
}
public Document getDocument() {
return doc;
}
public Element getDocumentElement() {
return doc.getDocumentElement();
}
public Node getNode(Node start, String strXPath) {
XPathExpression exp = getExpression(strXPath);
try {
return (Node) exp.evaluate(start, XPathConstants.NODE);
} catch (XPathExpressionException e) {
throw new RuntimeException("GetNode failed", e);
}
}
public Node getNode(String strXPath) {
return getNode(doc.getDocumentElement(), strXPath);
}
public NodeList getNodes(Node start, String strXPath) {
XPathExpression exp = getExpression(strXPath);
try {
return (NodeList) exp.evaluate(start, XPathConstants.NODESET);
} catch (XPathExpressionException e) {
throw new RuntimeException("GetNodes failed", e);
}
}
public NodeList getNodes(String strXPath) {
return getNodes(doc.getDocumentElement(), strXPath);
}
/**
* Gets the String content of the element at the specified XPath
*
* @param strXPath
* @return content of the specified XML element
*/
public String getElementContent(Node start, String strXPath) {
XPathExpression exp = getExpression(strXPath);
try {
return exp.evaluate(start);
} catch (XPathExpressionException e) {
throw new RuntimeException("getElementContent failed", e);
}
}
public String getElementContent(String strXPath) {
return getElementContent(doc.getDocumentElement(), strXPath);
}
/**
* Sets the content of the element elementName, at strXPath parent. If
* replace is true then the first found elementName under the parent element
* is replaced with the content. Otherwise a new element is always created.
*
* @param strXPath
* @param elementName
* @param content
* @param replace
*/
public void setElementContent(String strXPath, String elementName,
String content, boolean replace) {
Element parentElement = (Element) getNode(strXPath);
Element reqElement = null;
if (replace) {
reqElement = (Element) parentElement.getElementsByTagName(
elementName).item(0);
if (reqElement == null) {
reqElement = doc.createElement(elementName);
parentElement.appendChild(reqElement);
}
} else {
reqElement = doc.createElement(elementName);
parentElement.appendChild(reqElement);
}
reqElement.setTextContent(content);
}
/**
* Imports the XML content at the location specified by the XPath
* expression. If replace is true and the specified elementName is child of
* the XPath specified element, the first such element content is replaced
* with the imported XML.
*
* @param strXPath
* @param elementName
* @param content
* @param replace
*/
public void importElementContent(String strXPath, String elementName,
String content, boolean replace) {
Element element = (Element) getNode(strXPath);
NodeList elements = element.getElementsByTagName(elementName);
Element reqElement = (Element) ((elements != null && elements
.getLength() > 0) ? elements.item(0) : null);
try {
Document importedDoc = builder.parse(new InputSource(
new StringReader(content)));
Node imported = doc.importNode(importedDoc.getDocumentElement(),
true);
if (replace && reqElement != null)
element.replaceChild(imported, reqElement);
else
element.appendChild(imported);
} catch (Exception e) {
throw new RuntimeException("importElementContent failed", e);
}
}
public void writeTo(OutputStream os) {
OutputStreamWriter writer = new OutputStreamWriter(os);
Result result = new StreamResult(writer);
transform(result);
}
public void writeTo(File f) {
FileOutputStream fos = null;
try {
fos = new FileOutputStream(f);
writeTo(fos);
} catch (Exception e) {
} finally {
if (fos != null)
try {
fos.close();
} catch (IOException e) {
}
}
}
public void writeTo(String fn) {
writeTo(new File(fn));
}
public byte[] getDocumentAsBytes() {
ByteArrayOutputStream os = new ByteArrayOutputStream();
OutputStreamWriter writer = new OutputStreamWriter(os);
Result result = new StreamResult(writer);
transform(result);
return os.toByteArray();
}
public String getDocumentAsString() {
StringWriter stringWriter = new StringWriter();
Result result = new StreamResult(stringWriter);
transform(result);
return stringWriter.getBuffer().toString();
}
/**
* Gets the cached compiled XPath expression from cache, or compiles a new
* one and puts it in the cache.
*
* @param strXPath
* @return
*/
private XPathExpression getExpression(String strXPath) {
XPathExpression exp = expCache.get(strXPath);
if (exp == null) { // expresion not found in cache
try {
exp = xpath.compile(strXPath);
} catch (XPathExpressionException e) {
throw new RuntimeException("getExpression failed", e);
}
expCache.put(strXPath, exp);
}
return exp;
}
private void transform(Result target) {
if (transformer == null) {
TransformerFactory factory = TransformerFactory.newInstance();
try {
transformer = factory.newTransformer();
} catch (TransformerConfigurationException e) {
throw new RuntimeException("transform failed", e);
}
}
try {
transformer.transform(docSource, target);
} catch (TransformerException e) {
throw new RuntimeException("transform failed", e);
}
}
}