
eu.europa.esig.dss.XmlDom Maven / Gradle / Ivy
Go to download
Show more of this group Show more artifacts with this name
Show all versions of dss-spi Show documentation
Show all versions of dss-spi Show documentation
DSS Service Provider Interface contains the contract interface shared between the applet and the server-side of DSS.
/**
* DSS - Digital Signature Services
* Copyright (C) 2015 European Commission, provided under the CEF programme
*
* This file is part of the "DSS - Digital Signature Services" project.
*
* This library is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public
* License as published by the Free Software Foundation; either
* version 2.1 of the License, or (at your option) any later version.
*
* This library is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public
* License along with this library; if not, write to the Free Software
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
*/
package eu.europa.esig.dss;
import java.io.ByteArrayOutputStream;
import java.io.OutputStream;
import java.io.OutputStreamWriter;
import java.io.UnsupportedEncodingException;
import java.util.ArrayList;
import java.util.Date;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.StringTokenizer;
import javax.xml.transform.OutputKeys;
import javax.xml.transform.Transformer;
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.apache.commons.lang.StringUtils;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
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;
/**
* This class encapsulates an org.w3c.dom.Document. Its integrates the ability to execute XPath queries on XML
* documents.
*/
public class XmlDom {
private static final Logger LOG = LoggerFactory.getLogger(XmlDom.class);
public static final String NAMESPACE = "http://dss.esig.europa.eu/validation/diagnostic";
private static final String NS_PREFIX = "dss";
private static final XPathFactory factory = XPathFactory.newInstance();
private static final NamespaceContextMap nsContext;
private static final Map namespaces;
static {
namespaces = new HashMap();
namespaces.put(NS_PREFIX, NAMESPACE);
nsContext = new NamespaceContextMap();
nsContext.registerNamespace(NS_PREFIX, NAMESPACE);
}
public final Element rootElement;
String nameSpace;
public XmlDom(final Document document) {
this.rootElement = document.getDocumentElement();
nameSpace = rootElement.getNamespaceURI();
}
public XmlDom(final Element element) {
this.rootElement = element;
}
private static XPathExpression createXPathExpression(final String xpathString) {
final XPath xpath = factory.newXPath();
xpath.setNamespaceContext(nsContext);
try {
final XPathExpression expr = xpath.compile(xpathString);
return expr;
} catch (XPathExpressionException ex) {
throw new RuntimeException(ex);
}
}
private static NodeList getNodeList(final Node xmlNode, final String xpathString) {
try {
final XPathExpression expr = createXPathExpression(xpathString);
return (NodeList) expr.evaluate(xmlNode, XPathConstants.NODESET);
} catch (XPathExpressionException e) {
throw new RuntimeException(e);
}
}
/**
* The list of elements corresponding the given XPath query and parameters.
*
* @param xPath
* @param params
* @return
*/
public List getElements(final String xPath, final Object... params) {
try {
String xPath_ = format(xPath, params);
NodeList nodeList = getNodeList(rootElement, xPath_);
List list = new ArrayList();
for (int ii = 0; ii < nodeList.getLength(); ii++) {
Node node = nodeList.item(ii);
if ((node != null) && (node.getNodeType() == Node.ELEMENT_NODE)) {
list.add(new XmlDom((Element) node));
}
}
return list;
} catch (Exception e) {
String message = "XPath error: '" + xPath + "'.";
throw new DSSException(message, e);
}
}
public XmlDom getElement(final String xPath, final Object... params) {
try {
String xPath_ = format(xPath, params);
NodeList nodeList = getNodeList(rootElement, xPath_);
for (int ii = 0; ii < nodeList.getLength(); ii++) {
Node node = nodeList.item(ii);
if ((node != null) && (node.getNodeType() == Node.ELEMENT_NODE)) {
return new XmlDom((Element) node);
}
}
return null;
} catch (Exception e) {
String message = "XPath error: '" + xPath + "'.";
throw new DSSException(message, e);
}
}
/**
* @param xPath
* @param params
* @return
*/
private static String format(final String xPath, final Object... params) {
String formattedXPath;
if (params.length > 0) {
formattedXPath = String.format(xPath, params);
} else {
formattedXPath = xPath;
}
formattedXPath = addNamespacePrefix(formattedXPath);
return formattedXPath;
}
private static String addNamespacePrefix(final String formatedXPath) {
if (formatedXPath.startsWith("/dss:") || formatedXPath.startsWith("./dss:")) {
// Already formated.
return formatedXPath;
}
String formatedXPath_ = formatedXPath;
CharSequence from = "//";
CharSequence to = "{#double}/";
boolean special = formatedXPath_.indexOf("//") != -1;
if (special) {
formatedXPath_ = formatedXPath_.replace(from, to);
}
StringTokenizer tokenizer = new StringTokenizer(formatedXPath_, "/");
StringBuilder stringBuilder = new StringBuilder();
while (tokenizer.hasMoreTokens())
{
String token = tokenizer.nextToken();
final boolean isDot = ".".equals(token);
final boolean isCount = "count(".equals(token) || "count(.".equals(token);
final boolean isDoubleDot = "..".equals(token);
final boolean isAt = token.startsWith("@");
final boolean isText = token.equals("text()");
final boolean isDoubleSlash = token.equals("{#double}");
final String slash = isDot || isCount || isDoubleSlash ? "" : "/";
String prefix = isDot || isCount || isDoubleDot || isAt || isText || isDoubleSlash ? "" : "dss:";
stringBuilder.append(slash).append(prefix).append(token);
}
String normalizedXPath = stringBuilder.toString();
if (special) {
normalizedXPath = normalizedXPath.replace(to, from);
}
return normalizedXPath;
}
/**
* This method never returns null.
*
* @param xPath
* @param params
* @return {@code String} value or empty string
*/
public String getValue(final String xPath, final Object... params) {
String xPath_ = format(xPath, params);
NodeList nodeList = getNodeList(rootElement, xPath_);
if (nodeList.getLength() == 1) {
Node node = nodeList.item(0);
if (node.getNodeType() != Node.ELEMENT_NODE) {
String value = nodeList.item(0).getTextContent();
return value.trim();
}
}
return "";
}
public int getIntValue(final String xPath, final Object... params) {
String value = getValue(xPath, params);
try {
return Integer.parseInt(value);
} catch (Exception e) {
throw new DSSException(e);
}
}
public long getLongValue(final String xPath, final Object... params) {
String value = getValue(xPath, params);
try {
value = value.trim();
return Long.parseLong(value);
} catch (Exception e) {
throw new DSSException(e);
}
}
public boolean getBoolValue(final String xPath, final Object... params) {
String value = getValue(xPath, params);
if (value.equals("true")) {
return true;
} else if (value.isEmpty() || value.equals("false")) {
return false;
}
throw new DSSException("Expected values are: true, false and not '" + value + "'.");
}
public long getCountValue(final String xPath, final Object... params) {
String xpathString = format(xPath, params);
try {
XPathExpression xPathExpression = createXPathExpression(xpathString);
Double number = (Double) xPathExpression.evaluate(rootElement, XPathConstants.NUMBER);
return number.intValue();
} catch (XPathExpressionException e) {
throw new RuntimeException(e);
}
}
public boolean exists(final String xPath, final Object... params) {
XmlDom element = getElement(xPath, params);
return element != null;
}
public Date getTimeValue(final String xPath, final Object... params) {
String value = getValue(xPath, params);
return DSSUtils.parseDate(value);
}
public Date getTimeValueOrNull(final String xPath, final Object... params) {
String value = getValue(xPath, params);
if (value.isEmpty()) {
return null;
}
return DSSUtils.parseDate(value);
}
public String getText() {
try {
if (rootElement != null) {
return rootElement.getTextContent().trim();
}
} catch (Exception e) {
}
return null;
}
/**
* The name of this node, depending on its type;
*
* @return
*/
public String getName() {
return rootElement.getNodeName();
}
/**
* Retrieves an attribute value by name.
*
* @param attributeName
* @return
*/
public String getAttribute(final String attributeName) {
return rootElement.getAttribute(attributeName);
}
/**
* Retrieves an attribute value by name.
*
* @return
*/
public NamedNodeMap getAttributes() {
return rootElement.getAttributes();
}
/**
* Converts the list of {@code XmlDom} to {@code List} of {@code String}. The children of the node are not taken
* into account.
*
* @param xmlDomList the list of {@code XmlDom} to convert
* @return converted {@code List} of {@code String}.
*/
public static List convertToStringList(final List xmlDomList) {
final List stringList = new ArrayList();
for (final XmlDom xmlDom : xmlDomList) {
stringList.add(xmlDom.getText());
}
return stringList;
}
/**
* Converts the list of {@code XmlDom} to {@code Map} of {@code String}, {@code String}. The children of the node are not taken
* into account.
*
* @param xmlDomList the list of {@code XmlDom} to convert
* @param attributeName the name of the attribute to use as value
* @return converted {@code Map} of {@code String}, {@code String} corresponding to the element content and the attribute value.
*/
public static Map convertToStringMap(final List xmlDomList, final String attributeName) {
final Map stringMap = new HashMap();
for (final XmlDom xmlDom : xmlDomList) {
final String key = xmlDom.getText();
final String value = xmlDom.getAttribute(attributeName);
stringMap.put(key, value);
}
return stringMap;
}
/**
* Converts the list of {@code XmlDom} to {@code Map} of {@code String}, {@code Date}. The children of the node are not taken
* into account. If a problem is encountered during the conversion the pair key, value is ignored and a warning is logged.
*
* @param xmlDomList the list of {@code XmlDom} to convert
* @param attributeName the name of the attribute to use as value
* @return converted {@code Map} of {@code String}, {@code Date} corresponding to the element content and the attribute value.
*/
public static Map convertToStringDateMap(final List xmlDomList, final String attributeName) {
final Map stringMap = new HashMap();
for (final XmlDom xmlDom : xmlDomList) {
final String key = xmlDom.getText();
final String dateString = xmlDom.getAttribute(attributeName);
String format = xmlDom.getAttribute("Format");
if (StringUtils.isBlank(format)) {
format = "yyyy-MM-dd";
}
if (StringUtils.isBlank(dateString)) {
LOG.warn(String.format("The date is not defined for key '%s'!", key));
continue;
}
final Date date;
try {
date = DSSUtils.parseDate(format, dateString);
} catch (DSSException e) {
LOG.warn("The date conversion is not possible.", e);
continue;
}
stringMap.put(key, date);
}
return stringMap;
}
public byte[] toByteArray() {
if (rootElement != null) {
ByteArrayOutputStream byteArrayOutputStream = new ByteArrayOutputStream();
printDocument(rootElement, byteArrayOutputStream, false);
return byteArrayOutputStream.toByteArray();
}
return DSSUtils.EMPTY_BYTE_ARRAY;
}
@Override
public String toString() {
if (rootElement != null) {
ByteArrayOutputStream byteArrayOutputStream = new ByteArrayOutputStream();
printDocument(rootElement, byteArrayOutputStream, false);
return getUtf8String(byteArrayOutputStream.toByteArray());
}
return super.toString();
}
/**
* Constructs a new String
by decoding the specified array of bytes using the UTF-8 charset.
*
* @param bytes The bytes to be decoded into characters
* @return A new String
decoded from the specified array of bytes using the UTF-8 charset,
* or null
if the input byte array was null
.
* @throws IllegalStateException Thrown when a {@link UnsupportedEncodingException} is caught, which should never happen since the
* charset is required.
*/
private static String getUtf8String(byte[] bytes) {
if (bytes == null) {
return null;
}
try {
return new String(bytes, "UTF-8");
} catch (UnsupportedEncodingException e) {
throw new DSSException(e);
}
}
/**
* This method writes formatted {@link org.w3c.dom.Node} to the outputStream.
*
* @param node
* @param out
*/
private static void printDocument(final Node node, final OutputStream out, final boolean raw) {
try {
final TransformerFactory tf = TransformerFactory.newInstance();
final Transformer transformer = tf.newTransformer();
transformer.setOutputProperty(OutputKeys.OMIT_XML_DECLARATION, "no");
transformer.setOutputProperty(OutputKeys.METHOD, "xml");
if (!raw) {
transformer.setOutputProperty(OutputKeys.INDENT, "yes");
transformer.setOutputProperty("{http://xml.apache.org/xslt}indent-amount", "3");
}
transformer.setOutputProperty(OutputKeys.ENCODING, "UTF-8");
final DOMSource xmlSource = new DOMSource(node);
final OutputStreamWriter writer = new OutputStreamWriter(out, "UTF-8");
final StreamResult outputTarget = new StreamResult(writer);
transformer.transform(xmlSource, outputTarget);
} catch (Exception e) {
throw new DSSException(e);
}
}
public Element getRootElement() {
return rootElement;
}
}
© 2015 - 2025 Weber Informatics LLC | Privacy Policy