From 759ac5f42c6aff901dbeede4fbf1a1d2e08cad0f Mon Sep 17 00:00:00 2001 From: Thomas Lenz Date: Wed, 4 Dec 2019 19:43:32 +0100 Subject: common EGIZ code-style refactoring --- .../at/gv/egiz/eaaf/core/impl/utils/DOMUtils.java | 1267 -------------------- .../at/gv/egiz/eaaf/core/impl/utils/DomUtils.java | 1158 ++++++++++++++++++ .../core/impl/utils/EAAFDomEntityResolver.java | 128 -- .../core/impl/utils/EaafDomEntityResolver.java | 118 ++ .../gv/egiz/eaaf/core/impl/utils/XPathUtils.java | 593 ++++----- 5 files changed, 1541 insertions(+), 1723 deletions(-) delete mode 100644 eaaf_core/src/main/java/at/gv/egiz/eaaf/core/impl/utils/DOMUtils.java create mode 100644 eaaf_core/src/main/java/at/gv/egiz/eaaf/core/impl/utils/DomUtils.java delete mode 100644 eaaf_core/src/main/java/at/gv/egiz/eaaf/core/impl/utils/EAAFDomEntityResolver.java create mode 100644 eaaf_core/src/main/java/at/gv/egiz/eaaf/core/impl/utils/EaafDomEntityResolver.java (limited to 'eaaf_core/src/main/java/at/gv/egiz/eaaf/core/impl/utils') diff --git a/eaaf_core/src/main/java/at/gv/egiz/eaaf/core/impl/utils/DOMUtils.java b/eaaf_core/src/main/java/at/gv/egiz/eaaf/core/impl/utils/DOMUtils.java deleted file mode 100644 index a9d33b74..00000000 --- a/eaaf_core/src/main/java/at/gv/egiz/eaaf/core/impl/utils/DOMUtils.java +++ /dev/null @@ -1,1267 +0,0 @@ -/******************************************************************************* - * Copyright 2017 Graz University of Technology - * EAAF-Core Components has been developed in a cooperation between EGIZ, - * A-SIT Plus, A-SIT, and Graz University of Technology. - * - * Licensed under the EUPL, Version 1.2 or - as soon they will be approved by - * the European Commission - subsequent versions of the EUPL (the "Licence"); - * You may not use this work except in compliance with the Licence. - * You may obtain a copy of the Licence at: - * https://joinup.ec.europa.eu/news/understanding-eupl-v12 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the Licence is distributed on an "AS IS" basis, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the Licence for the specific language governing permissions and - * limitations under the Licence. - * - * This product combines work with different licenses. See the "NOTICE" text - * file for details on the various modules and licenses. - * The "NOTICE" text file is part of the distribution. Any derivative works - * that you distribute must include a readable copy of the "NOTICE" text file. - *******************************************************************************/ -/******************************************************************************* - *******************************************************************************/ -/******************************************************************************* - *******************************************************************************/ - - -package at.gv.egiz.eaaf.core.impl.utils; - -import java.io.ByteArrayInputStream; -import java.io.ByteArrayOutputStream; -import java.io.IOException; -import java.io.InputStream; -import java.util.Collections; -import java.util.HashMap; -import java.util.HashSet; -import java.util.Iterator; -import java.util.List; -import java.util.Map; -import java.util.Map.Entry; -import java.util.Set; -import java.util.Vector; - -import javax.xml.parsers.DocumentBuilder; -import javax.xml.parsers.DocumentBuilderFactory; -import javax.xml.parsers.ParserConfigurationException; -import javax.xml.transform.OutputKeys; -import javax.xml.transform.Result; -import javax.xml.transform.Source; -import javax.xml.transform.Transformer; -import javax.xml.transform.TransformerException; -import javax.xml.transform.TransformerFactory; -import javax.xml.transform.dom.DOMSource; -import javax.xml.transform.stream.StreamResult; - -import org.apache.commons.io.IOUtils; -import org.apache.commons.lang3.StringUtils; -import org.apache.xerces.parsers.DOMParser; -import org.apache.xerces.parsers.SAXParser; -import org.apache.xerces.parsers.XMLGrammarPreparser; -import org.apache.xerces.util.SymbolTable; -import org.apache.xerces.util.XMLGrammarPoolImpl; -import org.apache.xerces.xni.grammars.XMLGrammarDescription; -import org.apache.xerces.xni.grammars.XMLGrammarPool; -import org.apache.xerces.xni.parser.XMLInputSource; -import org.slf4j.Logger; -import org.slf4j.LoggerFactory; -import org.w3c.dom.Attr; -import org.w3c.dom.Document; -import org.w3c.dom.DocumentFragment; -import org.w3c.dom.Element; -import org.w3c.dom.NamedNodeMap; -import org.w3c.dom.Node; -import org.w3c.dom.NodeList; -import org.xml.sax.EntityResolver; -import org.xml.sax.ErrorHandler; -import org.xml.sax.InputSource; -import org.xml.sax.SAXException; - -import at.gv.egiz.eaaf.core.api.data.XMLNamespaceConstants; - -/** - * Various utility functions for handling XML DOM trees. - * - * The parsing methods in this class make use of some features internal to the - * Xerces DOM parser, mainly for performance reasons. As soon as JAXP - * (currently at version 1.2) is better at schema handling, it should be used as - * the parser interface. - * - */ -public class DOMUtils { - private static final Logger log = LoggerFactory.getLogger(DOMUtils.class); - - /** Feature URI for namespace aware parsing. */ - private static final String NAMESPACES_FEATURE = - "http://xml.org/sax/features/namespaces"; - /** Feature URI for validating parsing. */ - private static final String VALIDATION_FEATURE = - "http://xml.org/sax/features/validation"; - /** Feature URI for schema validating parsing. */ - private static final String SCHEMA_VALIDATION_FEATURE = - "http://apache.org/xml/features/validation/schema"; - /** Feature URI for normalization of element/attribute values. */ - private static final String NORMALIZED_VALUE_FEATURE = - "http://apache.org/xml/features/validation/schema/normalized-value"; - /** Feature URI for parsing ignorable whitespace. */ - private static final String INCLUDE_IGNORABLE_WHITESPACE_FEATURE = - "http://apache.org/xml/features/dom/include-ignorable-whitespace"; - /** Feature URI for creating EntityReference nodes in the DOM tree. */ - private static final String CREATE_ENTITY_REF_NODES_FEATURE = - "http://apache.org/xml/features/dom/create-entity-ref-nodes"; - /** Property URI for providing external schema locations. */ - private static final String EXTERNAL_SCHEMA_LOCATION_PROPERTY = - "http://apache.org/xml/properties/schema/external-schemaLocation"; - /** Property URI for providing the external schema location for elements - * without a namespace. */ - private static final String EXTERNAL_NO_NAMESPACE_SCHEMA_LOCATION_PROPERTY = - "http://apache.org/xml/properties/schema/external-noNamespaceSchemaLocation"; - - private static final String EXTERNAL_GENERAL_ENTITIES_FEATURE = - "http://xml.org/sax/features/external-general-entities"; - - private static final String EXTERNAL_PARAMETER_ENTITIES_FEATURE = - "http://xml.org/sax/features/external-parameter-entities"; - - public static final String DISALLOW_DOCTYPE_FEATURE = - "http://apache.org/xml/features/disallow-doctype-decl"; - - - - /** Property URI for the Xerces grammar pool. */ - private static final String GRAMMAR_POOL = - org.apache.xerces.impl.Constants.XERCES_PROPERTY_PREFIX - + org.apache.xerces.impl.Constants.XMLGRAMMAR_POOL_PROPERTY; - /** A prime number for initializing the symbol table. */ - private static final int BIG_PRIME = 2039; - /** Symbol table for the grammar pool. */ - private static SymbolTable symbolTable = new SymbolTable(BIG_PRIME); - /** Xerces schema grammar pool. */ - private static XMLGrammarPool grammarPool = new XMLGrammarPoolImpl(); - /** Set holding the NamespaceURIs of the grammarPool, to prevent multiple - * entries of same grammars to the pool */ - private static Set grammarNamespaces; - - static { - grammarPool.lockPool(); - grammarNamespaces = new HashSet(); - } - - /** - * Preparse a schema and add it to the schema pool. - * The method only adds the schema to the pool if a schema having the same - * systemId (namespace URI) is not already present in the pool. - * - * @param inputStream An InputStream providing the contents of - * the schema. - * @param systemId The systemId (namespace URI) to use for the schema. - * @throws IOException An error occurred reading the schema. - */ - public static void addSchemaToPool(InputStream inputStream, String systemId) - throws IOException { - XMLGrammarPreparser preparser; - - if (!grammarNamespaces.contains(systemId)) { - - grammarNamespaces.add(systemId); - - // unlock the pool so that we can add another grammar - grammarPool.unlockPool(); - - // prepare the preparser - preparser = new XMLGrammarPreparser(symbolTable); - preparser.registerPreparser(XMLGrammarDescription.XML_SCHEMA, null); - preparser.setProperty(GRAMMAR_POOL, grammarPool); - preparser.setFeature(NAMESPACES_FEATURE, true); - preparser.setFeature(VALIDATION_FEATURE, true); - - // add the grammar to the pool - preparser.preparseGrammar( - XMLGrammarDescription.XML_SCHEMA, - new XMLInputSource(null, systemId, null, inputStream, null)); - - // lock the pool again so that schemas are not added automatically - grammarPool.lockPool(); - } - } - - /** - * Parse an XML document from an InputStream. - * - * @param inputStream The InputStream containing the XML - * document. - * @param validating If true, parse validating. - * @param externalSchemaLocations A String containing namespace - * URI to schema location pairs, the same way it is accepted by the xsi: - * schemaLocation attribute. - * @param externalNoNamespaceSchemaLocation The schema location of the - * schema for elements without a namespace, the same way it is accepted by the - * xsi:noNamespaceSchemaLocation attribute. - * @param entityResolver An EntityResolver to resolve external - * entities (schemas and DTDs). If null, it will not be set. - * @param errorHandler An ErrorHandler to decide what to do - * with parsing errors. If null, it will not be set. - * @return The parsed XML document as a DOM tree. - * @throws SAXException An error occurred parsing the document. - * @throws IOException An error occurred reading the document. - * @throws ParserConfigurationException An error occurred configuring the XML - * parser. - */ - public static Document parseDocument( - InputStream inputStream, - boolean validating, - String externalSchemaLocations, - String externalNoNamespaceSchemaLocation, - EntityResolver entityResolver, - ErrorHandler errorHandler, - Map parserFeatures) - throws SAXException, IOException, ParserConfigurationException { - - DOMParser parser; - -// class MyEntityResolver implements EntityResolver { -// -// public InputSource resolveEntity(String publicId, String systemId) -// throws SAXException, IOException { -// return new InputSource(new ByteArrayInputStream(new byte[0])); -// } -// } - - - //if Debug is enabled make a copy of inputStream to enable debug output in case of SAXException - byte buffer [] = null; - ByteArrayInputStream baStream = null; - if(true == log.isDebugEnabled()) { - buffer = IOUtils.toByteArray(inputStream); - baStream = new ByteArrayInputStream(buffer); - - } - - - - // create the DOM parser - if (symbolTable != null) { - parser = new DOMParser(symbolTable, grammarPool); - } else { - parser = new DOMParser(); - } - - // set parser features and properties - try { - parser.setFeature(NAMESPACES_FEATURE, true); - parser.setFeature(VALIDATION_FEATURE, validating); - parser.setFeature(SCHEMA_VALIDATION_FEATURE, validating); - parser.setFeature(NORMALIZED_VALUE_FEATURE, false); - parser.setFeature(INCLUDE_IGNORABLE_WHITESPACE_FEATURE, true); - parser.setFeature(CREATE_ENTITY_REF_NODES_FEATURE, false); - parser.setFeature(EXTERNAL_GENERAL_ENTITIES_FEATURE, false); - parser.setFeature(EXTERNAL_PARAMETER_ENTITIES_FEATURE, false); - - //set external added parser features - if (parserFeatures != null) { - for (Entry el : parserFeatures.entrySet()) { - String key = el.getKey(); - if (StringUtils.isNotEmpty(key)) { - Object value = el.getValue(); - if (value != null && value instanceof Boolean) - parser.setFeature(key, (boolean)value); - - else - log.warn("This XML parser only allows features with 'boolean' values"); - - } else - log.warn("Can not set 'null' feature to XML parser"); - } - } - - //fix XXE problem - //parser.setFeature("http://apache.org/xml/features/disallow-doctype-decl", true); - - - if (validating) { - if (externalSchemaLocations != null) { - parser.setProperty( - EXTERNAL_SCHEMA_LOCATION_PROPERTY, - externalSchemaLocations); - } - if (externalNoNamespaceSchemaLocation != null) { - parser.setProperty( - EXTERNAL_NO_NAMESPACE_SCHEMA_LOCATION_PROPERTY, - externalNoNamespaceSchemaLocation); - } - } - - // set entity resolver and error handler - if (entityResolver != null) { - parser.setEntityResolver(entityResolver); - } - if (errorHandler != null) { - parser.setErrorHandler(errorHandler); - } - - // parse the document and return it - // if debug is enabled: use copy of strem (baStream) else use orig stream - if(null != baStream) - parser.parse(new InputSource(baStream)); - else - parser.parse(new InputSource(inputStream)); - } catch(SAXException e) { - if(true == log.isDebugEnabled() && null != buffer) { - String xmlContent = new String(buffer); - log.debug("SAXException in:\n" + xmlContent); - } - throw(e); - } - - return parser.getDocument(); - } - - /** - * Parse an XML document from an InputStream. - * - * @param inputStream The InputStream containing the XML - * document. - * @param validating If true, parse validating. - * @param externalSchemaLocations A String containing namespace - * URI to schema location pairs, the same way it is accepted by the xsi: - * schemaLocation attribute. - * @param externalNoNamespaceSchemaLocation The schema location of the - * schema for elements without a namespace, the same way it is accepted by the - * xsi:noNamespaceSchemaLocation attribute. - * @param entityResolver An EntityResolver to resolve external - * entities (schemas and DTDs). If null, it will not be set. - * @param errorHandler An ErrorHandler to decide what to do - * with parsing errors. If null, it will not be set. - * @return The parsed XML document as a DOM tree. - * @throws SAXException An error occurred parsing the document. - * @throws IOException An error occurred reading the document. - * @throws ParserConfigurationException An error occurred configuring the XML - * parser. - */ - public static Document parseDocumentSimple(InputStream inputStream) - throws SAXException, IOException, ParserConfigurationException { - - DOMParser parser; - - parser = new DOMParser(); - // set parser features and properties - parser.setFeature(NAMESPACES_FEATURE, true); - parser.setFeature(VALIDATION_FEATURE, false); - parser.setFeature(SCHEMA_VALIDATION_FEATURE, false); - parser.setFeature(NORMALIZED_VALUE_FEATURE, false); - parser.setFeature(INCLUDE_IGNORABLE_WHITESPACE_FEATURE, true); - parser.setFeature(CREATE_ENTITY_REF_NODES_FEATURE, false); - - parser.parse(new InputSource(inputStream)); - - return parser.getDocument(); - } - - - /** - * Parse an XML document from an InputStream. - * - * It uses a MOAEntityResolver as the EntityResolver - * and a MOAErrorHandler as the ErrorHandler. - * - * @param inputStream The InputStream containing the XML - * document. - * @param validating If true, parse validating. - * @param externalSchemaLocations A String containing namespace - * URI to schema location pairs, the same way it is accepted by the xsi: - * schemaLocation attribute. - * @param externalNoNamespaceSchemaLocation The schema location of the - * schema for elements without a namespace, the same way it is accepted by the - * xsi:noNamespaceSchemaLocation attribute. - * @param parserFeatures - * @return The parsed XML document as a DOM tree. - * @throws SAXException An error occurred parsing the document. - * @throws IOException An error occurred reading the document. - * @throws ParserConfigurationException An error occurred configuring the XML - * parser. - */ - public static Document parseDocument( - InputStream inputStream, - boolean validating, - String externalSchemaLocations, - String externalNoNamespaceSchemaLocation, Map parserFeatures) - throws SAXException, IOException, ParserConfigurationException { - - - - return parseDocument( - inputStream, - validating, - externalSchemaLocations, - externalNoNamespaceSchemaLocation, - new EAAFDomEntityResolver(), - null, - parserFeatures); - } - - /** - * Parse an XML document from a String. - * - * It uses a MOAEntityResolver as the EntityResolver - * and a MOAErrorHandler as the ErrorHandler. - * - * @param xmlString The String containing the XML document. - * @param encoding The encoding of the XML document. - * @param validating If true, parse validating. - * @param externalSchemaLocations A String containing namespace - * URI to schema location pairs, the same way it is accepted by the xsi: - * schemaLocation attribute. - * @param externalNoNamespaceSchemaLocation The schema location of the - * schema for elements without a namespace, the same way it is accepted by the - * xsi:noNamespaceSchemaLocation attribute. - * @return The parsed XML document as a DOM tree. - * @throws SAXException An error occurred parsing the document. - * @throws IOException An error occurred reading the document. - * @throws ParserConfigurationException An error occurred configuring the XML - * parser. - */ - public static Document parseDocument( - String xmlString, - String encoding, - boolean validating, - String externalSchemaLocations, - String externalNoNamespaceSchemaLocation, - Map parserFeatures) - throws SAXException, IOException, ParserConfigurationException { - - InputStream in = new ByteArrayInputStream(xmlString.getBytes(encoding)); - return parseDocument( - in, - validating, - externalSchemaLocations, - externalNoNamespaceSchemaLocation, - parserFeatures); - } - - - /** - * Parse an XML document from a String. - * - * It uses a MOAEntityResolver as the EntityResolver - * and a MOAErrorHandler as the ErrorHandler. - * - * @param xmlString The String containing the XML document. - * @param encoding The encoding of the XML document. - * @param validating If true, parse validating. - * @param externalSchemaLocations A String containing namespace - * URI to schema location pairs, the same way it is accepted by the xsi: - * schemaLocation attribute. - * @param externalNoNamespaceSchemaLocation The schema location of the - * schema for elements without a namespace, the same way it is accepted by the - * xsi:noNamespaceSchemaLocation attribute. - * @return The parsed XML document as a DOM tree. - * @throws SAXException An error occurred parsing the document. - * @throws IOException An error occurred reading the document. - * @throws ParserConfigurationException An error occurred configuring the XML - * parser. - */ - public static Document parseDocument( - String xmlString, - String encoding, - boolean validating, - String externalSchemaLocations, - String externalNoNamespaceSchemaLocation) - throws SAXException, IOException, ParserConfigurationException { - - InputStream in = new ByteArrayInputStream(xmlString.getBytes(encoding)); - return parseDocument( - in, - validating, - externalSchemaLocations, - externalNoNamespaceSchemaLocation, - null); - } - - /** - * Parse an UTF-8 encoded XML document from a String. - * - * @param xmlString The String containing the XML document. - * @param validating If true, parse validating. - * @param externalSchemaLocations A String containing namespace - * URI to schema location pairs, the same way it is accepted by the xsi: - * schemaLocation attribute. - * @param externalNoNamespaceSchemaLocation The schema location of the - * schema for elements without a namespace, the same way it is accepted by the - * xsi:noNamespaceSchemaLocation attribute. - * @return The parsed XML document as a DOM tree. - * @throws SAXException An error occurred parsing the document. - * @throws IOException An error occurred reading the document. - * @throws ParserConfigurationException An error occurred configuring the XML - * parser. - */ - public static Document parseDocument( - String xmlString, - boolean validating, - String externalSchemaLocations, - String externalNoNamespaceSchemaLocation) - throws SAXException, IOException, ParserConfigurationException { - - return parseDocument( - xmlString, - "UTF-8", - validating, - externalSchemaLocations, - externalNoNamespaceSchemaLocation); - } - - /** - * A convenience method to parse an XML document validating. - * - * @param inputStream The InputStream containing the XML - * document. - * @return The root element of the parsed XML document. - * @throws SAXException An error occurred parsing the document. - * @throws IOException An error occurred reading the document. - * @throws ParserConfigurationException An error occurred configuring the XML - * parser. - */ - public static Element parseXmlValidating(InputStream inputStream) - throws ParserConfigurationException, SAXException, IOException { - return DOMUtils - .parseDocument(inputStream, true, XMLNamespaceConstants.ALL_SCHEMA_LOCATIONS, null, null) - .getDocumentElement(); - } - - /** - * A convenience method to parse an XML document validating. - * - * @param inputStream The InputStream containing the XML - * document. - * @param parserFeatures Set additional features to XML parser - * @return The root element of the parsed XML document. - * @throws SAXException An error occurred parsing the document. - * @throws IOException An error occurred reading the document. - * @throws ParserConfigurationException An error occurred configuring the XML - * parser. - */ - public static Element parseXmlValidating(InputStream inputStream, Map parserFeatures) - throws ParserConfigurationException, SAXException, IOException { - return DOMUtils - .parseDocument(inputStream, true, XMLNamespaceConstants.ALL_SCHEMA_LOCATIONS, null, parserFeatures) - .getDocumentElement(); - } - - /** - * A convenience method to parse an XML document non validating. - * This method disallow DocType declarations - * - * @param inputStream The InputStream containing the XML - * document. - * @return The root element of the parsed XML document. - * @throws SAXException An error occurred parsing the document. - * @throws IOException An error occurred reading the document. - * @throws ParserConfigurationException An error occurred configuring the XML - * parser. - */ - public static Element parseXmlNonValidating(InputStream inputStream) - throws ParserConfigurationException, SAXException, IOException { - return DOMUtils - .parseDocument(inputStream, false, XMLNamespaceConstants.ALL_SCHEMA_LOCATIONS, null, - Collections.unmodifiableMap(new HashMap() { - private static final long serialVersionUID = 1L; - { - put(DOMUtils.DISALLOW_DOCTYPE_FEATURE, true); - - } - })).getDocumentElement(); - } - - /** - * Schema validate a given DOM element. - * - * @param element The element to validate. - * @param externalSchemaLocations A String containing namespace - * URI to schema location pairs, the same way it is accepted by the xsi: - * schemaLocation attribute. - * @param externalNoNamespaceSchemaLocation The schema location of the - * schema for elements without a namespace, the same way it is accepted by the - * xsi:noNamespaceSchemaLocation attribute. - * @return true, if the element validates against - * the schemas declared in it. - * @throws SAXException An error occurred parsing the document. - * @throws IOException An error occurred reading the document from its - * serialized representation. - * @throws ParserConfigurationException An error occurred configuring the XML - * @throws TransformerException An error occurred serializing the element. - */ - public static boolean validateElement( - Element element, - String externalSchemaLocations, - String externalNoNamespaceSchemaLocation) - throws - ParserConfigurationException, - IOException, - SAXException, - TransformerException { - - byte[] docBytes; - SAXParser parser; - - // create the SAX parser - if (symbolTable != null) { - parser = new SAXParser(symbolTable, grammarPool); - } else { - parser = new SAXParser(); - } - - // serialize the document - docBytes = serializeNode(element, "UTF-8"); - - // set up parser features and attributes - parser.setFeature(NAMESPACES_FEATURE, true); - parser.setFeature(VALIDATION_FEATURE, true); - parser.setFeature(SCHEMA_VALIDATION_FEATURE, true); - parser.setFeature(EXTERNAL_GENERAL_ENTITIES_FEATURE, false); - parser.setFeature(DISALLOW_DOCTYPE_FEATURE, true); - - - if (externalSchemaLocations != null) { - parser.setProperty( - EXTERNAL_SCHEMA_LOCATION_PROPERTY, - externalSchemaLocations); - } - if (externalNoNamespaceSchemaLocation != null) { - parser.setProperty( - EXTERNAL_NO_NAMESPACE_SCHEMA_LOCATION_PROPERTY, - "externalNoNamespaceSchemaLocation"); - } - - // set up entity resolver and error handler - parser.setEntityResolver(new EAAFDomEntityResolver()); - - // parse validating - parser.parse(new InputSource(new ByteArrayInputStream(docBytes))); - return true; - } - - - /** - * Schema validate a given DOM element. - * - * @param element The element to validate. - * @param externalSchemaLocations A String containing namespace - * URI to schema location pairs, the same way it is accepted by the xsi: - * schemaLocation attribute. - * @param externalNoNamespaceSchemaLocation The schema location of the - * schema for elements without a namespace, the same way it is accepted by the - * xsi:noNamespaceSchemaLocation attribute. - * @return true, if the element validates against - * the schemas declared in it. - * @throws SAXException An error occurred parsing the document. - * @throws IOException An error occurred reading the document from its - * serialized representation. - * @throws ParserConfigurationException An error occurred configuring the XML - * @throws TransformerException An error occurred serializing the element. - */ - public static boolean validateElement( - Element element, - String externalSchemaLocations, - String externalNoNamespaceSchemaLocation, - EntityResolver entityResolver) - throws - ParserConfigurationException, - IOException, - SAXException, - TransformerException { - - byte[] docBytes; - SAXParser parser; - - // create the SAX parser - if (symbolTable != null) { - parser = new SAXParser(symbolTable, grammarPool); - } else { - parser = new SAXParser(); - } - - // serialize the document - docBytes = serializeNode(element, "UTF-8"); - - // set up parser features and attributes - parser.setFeature(NAMESPACES_FEATURE, true); - parser.setFeature(VALIDATION_FEATURE, true); - parser.setFeature(SCHEMA_VALIDATION_FEATURE, true); - - if (externalSchemaLocations != null) { - parser.setProperty( - EXTERNAL_SCHEMA_LOCATION_PROPERTY, - externalSchemaLocations); - } - if (externalNoNamespaceSchemaLocation != null) { - parser.setProperty( - EXTERNAL_NO_NAMESPACE_SCHEMA_LOCATION_PROPERTY, - "externalNoNamespaceSchemaLocation"); - } - - // set up entity resolver and error handler - parser.setEntityResolver(entityResolver); - - // parse validating - parser.parse(new InputSource(new ByteArrayInputStream(docBytes))); - return true; - } - - /** - * Serialize the given DOM node. - * - * The node will be serialized using the UTF-8 encoding. - * - * @param node The node to serialize. - * @return String The String representation of the given DOM - * node. - * @throws TransformerException An error occurred transforming the - * node to a String. - * @throws IOException An IO error occurred writing the node to a byte array. - */ - public static String serializeNode(Node node) - throws TransformerException, IOException { - return new String(serializeNode(node, "UTF-8", false), "UTF-8"); - } - - - /** - * Serialize the given DOM node. - * - * The node will be serialized using the UTF-8 encoding. - * - * @param node The node to serialize. - * @param omitXmlDeclaration The boolean value for omitting the XML Declaration. - * @return String The String representation of the given DOM - * node. - * @throws TransformerException An error occurred transforming the - * node to a String. - * @throws IOException An IO error occurred writing the node to a byte array. - */ - public static String serializeNode(Node node, boolean omitXmlDeclaration) - throws TransformerException, IOException { - return new String(serializeNode(node, "UTF-8", omitXmlDeclaration), "UTF-8"); - } - - /** - * Serialize the given DOM node. - * - * The node will be serialized using the UTF-8 encoding. - * - * @param node The node to serialize. - * @param omitXmlDeclaration The boolean value for omitting the XML Declaration. - * @param lineSeperator Sets the line seperator String of the parser - * @return String The String representation of the given DOM - * node. - * @throws TransformerException An error occurred transforming the - * node to a String. - * @throws IOException An IO error occurred writing the node to a byte array. - */ - public static String serializeNode(Node node, boolean omitXmlDeclaration, String lineSeperator) - throws TransformerException, IOException { - return new String(serializeNode(node, "UTF-8", omitXmlDeclaration, lineSeperator), "UTF-8"); - } - - /** - * Serialize the given DOM node to a byte array. - * - * @param node The node to serialize. - * @param xmlEncoding The XML encoding to use. - * @return The serialized node, as a byte array. Using a compatible encoding - * this can easily be converted into a String. - * @throws TransformerException An error occurred transforming the node to a - * byte array. - * @throws IOException An IO error occurred writing the node to a byte array. - */ - public static byte[] serializeNode(Node node, String xmlEncoding) - throws TransformerException, IOException { - return serializeNode(node, xmlEncoding, false); - } - - /** - * Serialize the given DOM node to a byte array. - * - * @param node The node to serialize. - * @param xmlEncoding The XML encoding to use. - * @param omitDeclaration The boolean value for omitting the XML Declaration. - * @return The serialized node, as a byte array. Using a compatible encoding - * this can easily be converted into a String. - * @throws TransformerException An error occurred transforming the node to a - * byte array. - * @throws IOException An IO error occurred writing the node to a byte array. - */ - public static byte[] serializeNode(Node node, String xmlEncoding, boolean omitDeclaration) - throws TransformerException, IOException { - return serializeNode(node, xmlEncoding, omitDeclaration, null); - } - - - /** - * Serialize the given DOM node to a byte array. - * - * @param node The node to serialize. - * @param xmlEncoding The XML encoding to use. - * @param omitDeclaration The boolean value for omitting the XML Declaration. - * @param lineSeperator Sets the line seperator String of the parser - * @return The serialized node, as a byte array. Using a compatible encoding - * this can easily be converted into a String. - * @throws TransformerException An error occurred transforming the node to a - * byte array. - * @throws IOException An IO error occurred writing the node to a byte array. - */ - public static byte[] serializeNode(Node node, String xmlEncoding, boolean omitDeclaration, String lineSeperator) - throws TransformerException, IOException { - - TransformerFactory transformerFactory = TransformerFactory.newInstance(); - Transformer transformer = transformerFactory.newTransformer(); - ByteArrayOutputStream bos = new ByteArrayOutputStream(16384); - - transformer.setOutputProperty(OutputKeys.METHOD, "xml"); - transformer.setOutputProperty(OutputKeys.ENCODING, xmlEncoding); - String omit = omitDeclaration ? "yes" : "no"; - transformer.setOutputProperty(OutputKeys.OMIT_XML_DECLARATION, omit); - if (null!=lineSeperator) { - transformer.setOutputProperty("{http://xml.apache.org/xalan}line-separator", lineSeperator);//does not work for xalan <= 2.5.1 - } - transformer.transform(new DOMSource(node), new StreamResult(bos)); - - bos.flush(); - bos.close(); - - return bos.toByteArray(); - } - - /** - * Return the text that a node contains. - * - * This routine: - *
    - *
  • Ignores comments and processing instructions.
  • - *
  • Concatenates TEXT nodes, CDATA nodes, and the results recursively - * processing EntityRef nodes.
  • - *
  • Ignores any element nodes in the sublist. (Other possible options are - * to recurse into element sublists or throw an exception.)
  • - *
- * - * @param node A DOM node from which to extract text. - * @return A String representing its contents. - */ - public static String getText(Node node) { - if (!node.hasChildNodes()) { - return ""; - } - - StringBuffer result = new StringBuffer(); - NodeList list = node.getChildNodes(); - - for (int i = 0; i < list.getLength(); i++) { - Node subnode = list.item(i); - if (subnode.getNodeType() == Node.TEXT_NODE) { - result.append(subnode.getNodeValue()); - } else if (subnode.getNodeType() == Node.CDATA_SECTION_NODE) { - result.append(subnode.getNodeValue()); - } else if (subnode.getNodeType() == Node.ENTITY_REFERENCE_NODE) { - // Recurse into the subtree for text - // (and ignore comments) - result.append(getText(subnode)); - } - } - return result.toString(); - } - - /** - * Build the namespace prefix to namespace URL mapping in effect for a given - * node. - * - * @param node The context node for which build the map. - * @return The namespace prefix to namespace URL mapping ( - * a String value to String value mapping). - */ - public static Map getNamespaceDeclarations(Node node) { - Map nsDecls = new HashMap(); - int i; - - do { - if (node.hasAttributes()) { - NamedNodeMap attrs = node.getAttributes(); - - for (i = 0; i < attrs.getLength(); i++) { - Attr attr = (Attr) attrs.item(i); - - // add prefix mapping if none exists - if ("xmlns".equals(attr.getPrefix()) - || "xmlns".equals(attr.getName())) { - - String nsPrefix = - attr.getPrefix() != null ? attr.getLocalName() : ""; - - if (nsDecls.get(nsPrefix) == null) { - nsDecls.put(nsPrefix, attr.getValue()); - } - } - } - } - } while ((node = node.getParentNode()) != null); - - return nsDecls; - } - - /** - * Add all namespace declarations declared in the parent(s) of a given - * element and used in the subtree of the given element to the given element. - * - * @param context The element to which to add the namespaces. - */ - public static void localizeNamespaceDeclarations(Element context) { - Node parent = context.getParentNode(); - - if (parent != null) { - Map namespaces = getNamespaceDeclarations(context.getParentNode()); - Set nsUris = collectNamespaceURIs(context); - Iterator iter; - - for (iter = namespaces.entrySet().iterator(); iter.hasNext();) { - Map.Entry e = (Map.Entry) iter.next(); - - if (nsUris.contains(e.getValue())) { - String prefix = (String) e.getKey(); - String nsUri = (String) e.getValue(); - String nsAttrName = "".equals(prefix) ? "xmlns" : "xmlns:" + prefix; - - context.setAttributeNS(XMLNamespaceConstants.XMLNS_NS_URI, nsAttrName, nsUri); - } - } - } - } - - /** - * Collect all the namespace URIs used in the subtree of a given element. - * - * @param context The element that should be searched for namespace URIs. - * @return All namespace URIs used in the subtree of context, - * including the ones used in context itself. - */ - public static Set collectNamespaceURIs(Element context) { - Set result = new HashSet(); - - collectNamespaceURIsImpl(context, result); - return result; - } - - /** - * A recursive method to do the work of collectNamespaceURIs. - * - * @param context The context element to evaluate. - * @param result The result, passed as a parameter to avoid unnecessary - * instantiations of Set. - */ - private static void collectNamespaceURIsImpl(Element context, Set result) { - NamedNodeMap attrs = context.getAttributes(); - NodeList childNodes = context.getChildNodes(); - String nsUri; - int i; - - // add the namespace of the context element - nsUri = context.getNamespaceURI(); - if (nsUri != null && nsUri != XMLNamespaceConstants.XMLNS_NS_URI) { - result.add(nsUri); - } - - // add all namespace URIs from attributes - for (i = 0; i < attrs.getLength(); i++) { - nsUri = attrs.item(i).getNamespaceURI(); - if (nsUri != null && nsUri != XMLNamespaceConstants.XMLNS_NS_URI) { - result.add(nsUri); - } - } - - // add all namespaces from subelements - for (i = 0; i < childNodes.getLength(); i++) { - Node node = childNodes.item(i); - - if (node.getNodeType() == Node.ELEMENT_NODE) { - collectNamespaceURIsImpl((Element) node, result); - } - } - } - - /** - * Check, that each attribute node in the given NodeList has its - * parent in the NodeList as well. - * - * @param nodes The NodeList to check. - * @return true, if each attribute node in nodes - * has its parent in nodes as well. - */ - public static boolean checkAttributeParentsInNodeList(NodeList nodes) { - Set nodeSet = new HashSet(); - int i; - - // put the nodes into the nodeSet - for (i = 0; i < nodes.getLength(); i++) { - nodeSet.add(nodes.item(i)); - } - - // check that each attribute node's parent is in the node list - for (i = 0; i < nodes.getLength(); i++) { - Node n = nodes.item(i); - - if (n.getNodeType() == Node.ATTRIBUTE_NODE) { - Attr attr = (Attr) n; - Element owner = attr.getOwnerElement(); - - if (owner == null) { - if (!isNamespaceDeclaration(attr)) { - return false; - } - } - - if (!nodeSet.contains(owner) && !isNamespaceDeclaration(attr)) { - return false; - } - } - } - - return true; - } - - /** - * Convert an unstructured NodeList into a - * DocumentFragment. - * - * @param nodeList Contains the node list to be converted into a DOM - * DocumentFragment. - * @return the resulting DocumentFragment. The DocumentFragment will be - * backed by a new DOM Document, i.e. all noded of the node list will be - * cloned. - * @throws ParserConfigurationException An error occurred creating the - * DocumentFragment. - * @precondition The nodes in the node list appear in document order - * @precondition for each Attr node in the node list, the owning Element is - * in the node list as well. - * @precondition each Element or Attr node in the node list is namespace - * aware. - */ - public static DocumentFragment nodeList2DocumentFragment(NodeList nodeList) - throws ParserConfigurationException { - - DocumentBuilder builder = - DocumentBuilderFactory.newInstance().newDocumentBuilder(); - Document doc = builder.newDocument(); - DocumentFragment result = doc.createDocumentFragment(); - - if (null == nodeList || nodeList.getLength() == 0) { - return result; - } - - int currPos = 0; - currPos = - nodeList2DocumentFragment(nodeList, currPos, result, null, null) + 1; - - while (currPos < nodeList.getLength()) { - currPos = - nodeList2DocumentFragment(nodeList, currPos, result, null, null) + 1; - } - return result; - } - - /** - * Helper method for the nodeList2DocumentFragment. - * - * @param nodeList The NodeList to convert. - * @param currPos The current position in the nodeList. - * @param result The resulting DocumentFragment. - * @param currOrgElem The current original element. - * @param currClonedElem The current cloned element. - * @return The current position. - */ - private static int nodeList2DocumentFragment( - NodeList nodeList, - int currPos, - DocumentFragment result, - Element currOrgElem, - Element currClonedElem) { - - while (currPos < nodeList.getLength()) { - Node currentNode = nodeList.item(currPos); - switch (currentNode.getNodeType()) { - case Node.COMMENT_NODE : - case Node.PROCESSING_INSTRUCTION_NODE : - case Node.TEXT_NODE : - { - // Append current node either to resulting DocumentFragment or to - // current cloned Element - if (null == currClonedElem) { - result.appendChild( - result.getOwnerDocument().importNode(currentNode, false)); - } else { - // Stop processing if current Node is not a descendant of - // current Element - if (!isAncestor(currOrgElem, currentNode)) { - return --currPos; - } - - currClonedElem.appendChild( - result.getOwnerDocument().importNode(currentNode, false)); - } - break; - } - - case Node.ELEMENT_NODE : - { - Element nextCurrOrgElem = (Element) currentNode; - Element nextCurrClonedElem = - result.getOwnerDocument().createElementNS( - nextCurrOrgElem.getNamespaceURI(), - nextCurrOrgElem.getNodeName()); - - // Append current Node either to resulting DocumentFragment or to - // current cloned Element - if (null == currClonedElem) { - result.appendChild(nextCurrClonedElem); - currOrgElem = nextCurrOrgElem; - currClonedElem = nextCurrClonedElem; - } else { - // Stop processing if current Node is not a descendant of - // current Element - if (!isAncestor(currOrgElem, currentNode)) { - return --currPos; - } - - currClonedElem.appendChild(nextCurrClonedElem); - } - - // Process current Node (of type Element) recursively - currPos = - nodeList2DocumentFragment( - nodeList, - ++currPos, - result, - nextCurrOrgElem, - nextCurrClonedElem); - - break; - } - - case Node.ATTRIBUTE_NODE : - { - Attr currAttr = (Attr) currentNode; - - // GK 20030411: Hack to overcome problems with IAIK IXSIL - if (currAttr.getOwnerElement() == null) - break; - if (currClonedElem == null) - break; - - // currClonedElem must be the owner Element of currAttr if - // preconditions are met - currClonedElem.setAttributeNS( - currAttr.getNamespaceURI(), - currAttr.getNodeName(), - currAttr.getValue()); - break; - } - - default : - { - // All other nodes will be ignored - } - } - - currPos++; - } - - return currPos; - } - - /** - * Check, if the given attribute is a namespace declaration. - * - * @param attr The attribute to check. - * @return true, if the attribute is a namespace declaration, - * false otherwise. - */ - private static boolean isNamespaceDeclaration(Attr attr) { - return XMLNamespaceConstants.XMLNS_NS_URI.equals(attr.getNamespaceURI()); - } - - /** - * Check, if a given DOM element is an ancestor of a given node. - * - * @param candAnc The DOM element to check for being the ancestor. - * @param cand The node to check for being the child. - * @return true, if candAnc is an (indirect) - * ancestor of cand; false otherwise. - */ - public static boolean isAncestor(Element candAnc, Node cand) { - Node currPar = cand.getParentNode(); - - while (currPar != null) { - if (candAnc == currPar) - return true; - currPar = currPar.getParentNode(); - } - return false; - } - - /** - * Selects the (first) element from a node list and returns it. - * - * @param nl The NodeList to get the element from. - * @return The (first) element included in the node list or null - * if the node list is null or empty or no element is - * included in the list. - */ - public static Element getElementFromNodeList (NodeList nl) { - if ((nl == null) || (nl.getLength() == 0)) { - return null; - } - for (int i=0; i + * The parsing methods in this class make use of some features internal to the Xerces DOM parser, + * mainly for performance reasons. As soon as JAXP (currently at version 1.2) is better at schema + * handling, it should be used as the parser interface. + *

+ * + */ +public class DomUtils { + private static final Logger log = LoggerFactory.getLogger(DomUtils.class); + + /** Feature URI for namespace aware parsing. */ + private static final String NAMESPACES_FEATURE = "http://xml.org/sax/features/namespaces"; + /** Feature URI for validating parsing. */ + private static final String VALIDATION_FEATURE = "http://xml.org/sax/features/validation"; + /** Feature URI for schema validating parsing. */ + private static final String SCHEMA_VALIDATION_FEATURE = + "http://apache.org/xml/features/validation/schema"; + /** Feature URI for normalization of element/attribute values. */ + private static final String NORMALIZED_VALUE_FEATURE = + "http://apache.org/xml/features/validation/schema/normalized-value"; + /** Feature URI for parsing ignorable whitespace. */ + private static final String INCLUDE_IGNORABLE_WHITESPACE_FEATURE = + "http://apache.org/xml/features/dom/include-ignorable-whitespace"; + /** Feature URI for creating EntityReference nodes in the DOM tree. */ + private static final String CREATE_ENTITY_REF_NODES_FEATURE = + "http://apache.org/xml/features/dom/create-entity-ref-nodes"; + /** Property URI for providing external schema locations. */ + private static final String EXTERNAL_SCHEMA_LOCATION_PROPERTY = + "http://apache.org/xml/properties/schema/external-schemaLocation"; + /** + * Property URI for providing the external schema location for elements without a namespace. + */ + private static final String EXTERNAL_NO_NAMESPACE_SCHEMA_LOCATION_PROPERTY = + "http://apache.org/xml/properties/schema/external-noNamespaceSchemaLocation"; + + private static final String EXTERNAL_GENERAL_ENTITIES_FEATURE = + "http://xml.org/sax/features/external-general-entities"; + + private static final String EXTERNAL_PARAMETER_ENTITIES_FEATURE = + "http://xml.org/sax/features/external-parameter-entities"; + + public static final String DISALLOW_DOCTYPE_FEATURE = + "http://apache.org/xml/features/disallow-doctype-decl"; + + + + /** Property URI for the Xerces grammar pool. */ + private static final String GRAMMAR_POOL = org.apache.xerces.impl.Constants.XERCES_PROPERTY_PREFIX + + org.apache.xerces.impl.Constants.XMLGRAMMAR_POOL_PROPERTY; + /** A prime number for initializing the symbol table. */ + private static final int BIG_PRIME = 2039; + /** Symbol table for the grammar pool. */ + private static SymbolTable symbolTable = new SymbolTable(BIG_PRIME); + /** Xerces schema grammar pool. */ + private static XMLGrammarPool grammarPool = new XMLGrammarPoolImpl(); + /** + * Set holding the NamespaceURIs of the grammarPool, to prevent multiple entries of same grammars + * to the pool. + */ + private static Set grammarNamespaces; + + static { + grammarPool.lockPool(); + grammarNamespaces = new HashSet(); + } + + /** + * Preparse a schema and add it to the schema pool. The method only adds the schema to the pool if + * a schema having the same systemId (namespace URI) is not already present in the + * pool. + * + * @param inputStream An InputStream providing the contents of the schema. + * @param systemId The systemId (namespace URI) to use for the schema. + * @throws IOException An error occurred reading the schema. + */ + public static void addSchemaToPool(final InputStream inputStream, final String systemId) + throws IOException { + XMLGrammarPreparser preparser; + + if (!grammarNamespaces.contains(systemId)) { + + grammarNamespaces.add(systemId); + + // unlock the pool so that we can add another grammar + grammarPool.unlockPool(); + + // prepare the preparser + preparser = new XMLGrammarPreparser(symbolTable); + preparser.registerPreparser(XMLGrammarDescription.XML_SCHEMA, null); + preparser.setProperty(GRAMMAR_POOL, grammarPool); + preparser.setFeature(NAMESPACES_FEATURE, true); + preparser.setFeature(VALIDATION_FEATURE, true); + + // add the grammar to the pool + preparser.preparseGrammar(XMLGrammarDescription.XML_SCHEMA, + new XMLInputSource(null, systemId, null, inputStream, null)); + + // lock the pool again so that schemas are not added automatically + grammarPool.lockPool(); + } + } + + /** + * Parse an XML document from an InputStream. + * + *

+ * It uses a MOAEntityResolver as the EntityResolver and a + * MOAErrorHandler as the ErrorHandler. + *

+ * + * @param inputStream The InputStream containing the XML document. + * @param validating If true, parse validating. + * @param externalSchemaLocations A String containing namespace URI to schema + * location pairs, the same way it is accepted by the xsi: + * schemaLocation attribute. + * @param externalNoNamespaceSchemaLocation The schema location of the schema for elements without + * a namespace, the same way it is accepted by the + * xsi:noNamespaceSchemaLocation attribute. + * @param parserFeatures Map of features that should be set into XML parser + * @return The parsed XML document as a DOM tree. + * @throws SAXException An error occurred parsing the document. + * @throws IOException An error occurred reading the document. + * @throws ParserConfigurationException An error occurred configuring the XML parser. + */ + public static Document parseDocument(final InputStream inputStream, final boolean validating, + final String externalSchemaLocations, final String externalNoNamespaceSchemaLocation, + final Map parserFeatures) + throws SAXException, IOException, ParserConfigurationException { + + return parseDocument(inputStream, validating, externalSchemaLocations, + externalNoNamespaceSchemaLocation, new EaafDomEntityResolver(), null, parserFeatures); + } + + /** + * Parse an XML document from a String. + * + *

+ * It uses a MOAEntityResolver as the EntityResolver and a + * MOAErrorHandler as the ErrorHandler. + *

+ * + * @param xmlString The String containing the XML document. + * @param encoding The encoding of the XML document. + * @param validating If true, parse validating. + * @param externalSchemaLocations A String containing namespace URI to schema + * location pairs, the same way it is accepted by the xsi: + * schemaLocation attribute. + * @param externalNoNamespaceSchemaLocation The schema location of the schema for elements without + * a namespace, the same way it is accepted by the + * xsi:noNamespaceSchemaLocation attribute. + * @return The parsed XML document as a DOM tree. + * @throws SAXException An error occurred parsing the document. + * @throws IOException An error occurred reading the document. + * @throws ParserConfigurationException An error occurred configuring the XML parser. + */ + public static Document parseDocument(final String xmlString, final String encoding, + final boolean validating, final String externalSchemaLocations, + final String externalNoNamespaceSchemaLocation, final Map parserFeatures) + throws SAXException, IOException, ParserConfigurationException { + + final InputStream in = new ByteArrayInputStream(xmlString.getBytes(encoding)); + return parseDocument(in, validating, externalSchemaLocations, externalNoNamespaceSchemaLocation, + parserFeatures); + } + + /** + * Parse an XML document from a String. + * + *

+ * It uses a MOAEntityResolver as the EntityResolver and a + * MOAErrorHandler as the ErrorHandler. + *

+ * + * @param xmlString The String containing the XML document. + * @param encoding The encoding of the XML document. + * @param validating If true, parse validating. + * @param externalSchemaLocations A String containing namespace URI to schema + * location pairs, the same way it is accepted by the xsi: + * schemaLocation attribute. + * @param externalNoNamespaceSchemaLocation The schema location of the schema for elements without + * a namespace, the same way it is accepted by the + * xsi:noNamespaceSchemaLocation attribute. + * @return The parsed XML document as a DOM tree. + * @throws SAXException An error occurred parsing the document. + * @throws IOException An error occurred reading the document. + * @throws ParserConfigurationException An error occurred configuring the XML parser. + */ + public static Document parseDocument(final String xmlString, final String encoding, + final boolean validating, final String externalSchemaLocations, + final String externalNoNamespaceSchemaLocation) + throws SAXException, IOException, ParserConfigurationException { + + final InputStream in = new ByteArrayInputStream(xmlString.getBytes(encoding)); + return parseDocument(in, validating, externalSchemaLocations, externalNoNamespaceSchemaLocation, + null); + } + + /** + * Parse an UTF-8 encoded XML document from a String. + * + * @param xmlString The String containing the XML document. + * @param validating If true, parse validating. + * @param externalSchemaLocations A String containing namespace URI to schema + * location pairs, the same way it is accepted by the xsi: + * schemaLocation attribute. + * @param externalNoNamespaceSchemaLocation The schema location of the schema for elements without + * a namespace, the same way it is accepted by the + * xsi:noNamespaceSchemaLocation attribute. + * @return The parsed XML document as a DOM tree. + * @throws SAXException An error occurred parsing the document. + * @throws IOException An error occurred reading the document. + * @throws ParserConfigurationException An error occurred configuring the XML parser. + */ + public static Document parseDocument(final String xmlString, final boolean validating, + final String externalSchemaLocations, final String externalNoNamespaceSchemaLocation) + throws SAXException, IOException, ParserConfigurationException { + + return parseDocument(xmlString, "UTF-8", validating, externalSchemaLocations, + externalNoNamespaceSchemaLocation); + } + + /** + * Parse an XML document from an InputStream. + * + * @param inputStream The InputStream containing the XML document. + * @param validating If true, parse validating. + * @param externalSchemaLocations A String containing namespace URI to schema + * location pairs, the same way it is accepted by the xsi: + * schemaLocation attribute. + * @param externalNoNamespaceSchemaLocation The schema location of the schema for elements without + * a namespace, the same way it is accepted by the + * xsi:noNamespaceSchemaLocation attribute. + * @param entityResolver An EntityResolver to resolve external entities (schemas and + * DTDs). If null, it will not be set. + * @param errorHandler An ErrorHandler to decide what to do with parsing errors. If + * null, it will not be set. + * @return The parsed XML document as a DOM tree. + * @throws SAXException An error occurred parsing the document. + * @throws IOException An error occurred reading the document. + * @throws ParserConfigurationException An error occurred configuring the XML parser. + */ + public static Document parseDocument(final InputStream inputStream, final boolean validating, + final String externalSchemaLocations, final String externalNoNamespaceSchemaLocation, + final EntityResolver entityResolver, final ErrorHandler errorHandler, + final Map parserFeatures) + throws SAXException, IOException, ParserConfigurationException { + + DOMParser parser; + + // class MyEntityResolver implements EntityResolver { + // + // public InputSource resolveEntity(String publicId, String systemId) + // throws SAXException, IOException { + // return new InputSource(new ByteArrayInputStream(new byte[0])); + // } + // } + + + // if Debug is enabled make a copy of inputStream to enable debug output in case of SAXException + byte[] buffer = null; + ByteArrayInputStream baStream = null; + if (true == log.isDebugEnabled()) { + buffer = IOUtils.toByteArray(inputStream); + baStream = new ByteArrayInputStream(buffer); + + } + + + + // create the DOM parser + if (symbolTable != null) { + parser = new DOMParser(symbolTable, grammarPool); + } else { + parser = new DOMParser(); + } + + // set parser features and properties + try { + parser.setFeature(NAMESPACES_FEATURE, true); + parser.setFeature(VALIDATION_FEATURE, validating); + parser.setFeature(SCHEMA_VALIDATION_FEATURE, validating); + parser.setFeature(NORMALIZED_VALUE_FEATURE, false); + parser.setFeature(INCLUDE_IGNORABLE_WHITESPACE_FEATURE, true); + parser.setFeature(CREATE_ENTITY_REF_NODES_FEATURE, false); + parser.setFeature(EXTERNAL_GENERAL_ENTITIES_FEATURE, false); + parser.setFeature(EXTERNAL_PARAMETER_ENTITIES_FEATURE, false); + + // set external added parser features + if (parserFeatures != null) { + for (final Entry el : parserFeatures.entrySet()) { + final String key = el.getKey(); + if (StringUtils.isNotEmpty(key)) { + final Object value = el.getValue(); + if (value != null && value instanceof Boolean) { + parser.setFeature(key, (boolean) value); + } else { + log.warn("This XML parser only allows features with 'boolean' values"); + } + + } else { + log.warn("Can not set 'null' feature to XML parser"); + } + } + } + + // fix XXE problem + // parser.setFeature("http://apache.org/xml/features/disallow-doctype-decl", true); + + + if (validating) { + if (externalSchemaLocations != null) { + parser.setProperty(EXTERNAL_SCHEMA_LOCATION_PROPERTY, externalSchemaLocations); + } + if (externalNoNamespaceSchemaLocation != null) { + parser.setProperty(EXTERNAL_NO_NAMESPACE_SCHEMA_LOCATION_PROPERTY, + externalNoNamespaceSchemaLocation); + } + } + + // set entity resolver and error handler + if (entityResolver != null) { + parser.setEntityResolver(entityResolver); + } + if (errorHandler != null) { + parser.setErrorHandler(errorHandler); + } + + // parse the document and return it + // if debug is enabled: use copy of strem (baStream) else use orig stream + if (null != baStream) { + parser.parse(new InputSource(baStream)); + } else { + parser.parse(new InputSource(inputStream)); + } + } catch (final SAXException e) { + if (true == log.isDebugEnabled() && null != buffer) { + final String xmlContent = new String(buffer, "UTF-8"); + log.debug("SAXException in:\n" + xmlContent); + } + throw (e); + } + + return parser.getDocument(); + } + + /** + * Simple document parser. + * + * @param inputStream data to parse + * @return Element + * @throws SAXException In case of an error + * @throws IOException In case of an error + * @throws ParserConfigurationException In case of an error + */ + public static Document parseDocumentSimple(final InputStream inputStream) + throws SAXException, IOException, ParserConfigurationException { + + DOMParser parser; + + parser = new DOMParser(); + // set parser features and properties + parser.setFeature(NAMESPACES_FEATURE, true); + parser.setFeature(VALIDATION_FEATURE, false); + parser.setFeature(SCHEMA_VALIDATION_FEATURE, false); + parser.setFeature(NORMALIZED_VALUE_FEATURE, false); + parser.setFeature(INCLUDE_IGNORABLE_WHITESPACE_FEATURE, true); + parser.setFeature(CREATE_ENTITY_REF_NODES_FEATURE, false); + + parser.parse(new InputSource(inputStream)); + + return parser.getDocument(); + } + + + + + + + + + + + + /** + * A convenience method to parse an XML document validating. + * + * @param inputStream The InputStream containing the XML document. + * @return The root element of the parsed XML document. + * @throws SAXException An error occurred parsing the document. + * @throws IOException An error occurred reading the document. + * @throws ParserConfigurationException An error occurred configuring the XML parser. + */ + public static Element parseXmlValidating(final InputStream inputStream) + throws ParserConfigurationException, SAXException, IOException { + return DomUtils + .parseDocument(inputStream, true, XMLNamespaceConstants.ALL_SCHEMA_LOCATIONS, null, null) + .getDocumentElement(); + } + + /** + * A convenience method to parse an XML document validating. + * + * @param inputStream The InputStream containing the XML document. + * @param parserFeatures Set additional features to XML parser + * @return The root element of the parsed XML document. + * @throws SAXException An error occurred parsing the document. + * @throws IOException An error occurred reading the document. + * @throws ParserConfigurationException An error occurred configuring the XML parser. + */ + public static Element parseXmlValidating(final InputStream inputStream, + final Map parserFeatures) + throws ParserConfigurationException, SAXException, IOException { + return DomUtils.parseDocument(inputStream, true, XMLNamespaceConstants.ALL_SCHEMA_LOCATIONS, + null, parserFeatures).getDocumentElement(); + } + + /** + * A convenience method to parse an XML document non validating. This method disallow DocType + * declarations + * + * @param inputStream The InputStream containing the XML document. + * @return The root element of the parsed XML document. + * @throws SAXException An error occurred parsing the document. + * @throws IOException An error occurred reading the document. + * @throws ParserConfigurationException An error occurred configuring the XML parser. + */ + public static Element parseXmlNonValidating(final InputStream inputStream) + throws ParserConfigurationException, SAXException, IOException { + return DomUtils.parseDocument(inputStream, false, XMLNamespaceConstants.ALL_SCHEMA_LOCATIONS, + null, Collections.unmodifiableMap(new HashMap() { + private static final long serialVersionUID = 1L; + { + put(DomUtils.DISALLOW_DOCTYPE_FEATURE, true); + + } + })).getDocumentElement(); + } + + /** + * Schema validate a given DOM element. + * + * @param element The element to validate. + * @param externalSchemaLocations A String containing namespace URI to schema + * location pairs, the same way it is accepted by the xsi: + * schemaLocation attribute. + * @param externalNoNamespaceSchemaLocation The schema location of the schema for elements without + * a namespace, the same way it is accepted by the + * xsi:noNamespaceSchemaLocation attribute. + * @return true, if the element validates against the schemas declared + * in it. + * @throws SAXException An error occurred parsing the document. + * @throws IOException An error occurred reading the document from its serialized representation. + * @throws ParserConfigurationException An error occurred configuring the XML + * @throws TransformerException An error occurred serializing the element. + */ + public static boolean validateElement(final Element element, final String externalSchemaLocations, + final String externalNoNamespaceSchemaLocation) + throws ParserConfigurationException, IOException, SAXException, TransformerException { + + byte[] docBytes; + SAXParser parser; + + // create the SAX parser + if (symbolTable != null) { + parser = new SAXParser(symbolTable, grammarPool); + } else { + parser = new SAXParser(); + } + + // serialize the document + docBytes = serializeNode(element, "UTF-8"); + + // set up parser features and attributes + parser.setFeature(NAMESPACES_FEATURE, true); + parser.setFeature(VALIDATION_FEATURE, true); + parser.setFeature(SCHEMA_VALIDATION_FEATURE, true); + parser.setFeature(EXTERNAL_GENERAL_ENTITIES_FEATURE, false); + parser.setFeature(DISALLOW_DOCTYPE_FEATURE, true); + + + if (externalSchemaLocations != null) { + parser.setProperty(EXTERNAL_SCHEMA_LOCATION_PROPERTY, externalSchemaLocations); + } + if (externalNoNamespaceSchemaLocation != null) { + parser.setProperty(EXTERNAL_NO_NAMESPACE_SCHEMA_LOCATION_PROPERTY, + "externalNoNamespaceSchemaLocation"); + } + + // set up entity resolver and error handler + parser.setEntityResolver(new EaafDomEntityResolver()); + + // parse validating + parser.parse(new InputSource(new ByteArrayInputStream(docBytes))); + return true; + } + + + /** + * Schema validate a given DOM element. + * + * @param element The element to validate. + * @param externalSchemaLocations A String containing namespace URI to schema + * location pairs, the same way it is accepted by the xsi: + * schemaLocation attribute. + * @param externalNoNamespaceSchemaLocation The schema location of the schema for elements without + * a namespace, the same way it is accepted by the + * xsi:noNamespaceSchemaLocation attribute. + * @return true, if the element validates against the schemas declared + * in it. + * @throws SAXException An error occurred parsing the document. + * @throws IOException An error occurred reading the document from its serialized representation. + * @throws ParserConfigurationException An error occurred configuring the XML + * @throws TransformerException An error occurred serializing the element. + */ + public static boolean validateElement(final Element element, final String externalSchemaLocations, + final String externalNoNamespaceSchemaLocation, final EntityResolver entityResolver) + throws ParserConfigurationException, IOException, SAXException, TransformerException { + + byte[] docBytes; + SAXParser parser; + + // create the SAX parser + if (symbolTable != null) { + parser = new SAXParser(symbolTable, grammarPool); + } else { + parser = new SAXParser(); + } + + // serialize the document + docBytes = serializeNode(element, "UTF-8"); + + // set up parser features and attributes + parser.setFeature(NAMESPACES_FEATURE, true); + parser.setFeature(VALIDATION_FEATURE, true); + parser.setFeature(SCHEMA_VALIDATION_FEATURE, true); + + if (externalSchemaLocations != null) { + parser.setProperty(EXTERNAL_SCHEMA_LOCATION_PROPERTY, externalSchemaLocations); + } + if (externalNoNamespaceSchemaLocation != null) { + parser.setProperty(EXTERNAL_NO_NAMESPACE_SCHEMA_LOCATION_PROPERTY, + "externalNoNamespaceSchemaLocation"); + } + + // set up entity resolver and error handler + parser.setEntityResolver(entityResolver); + + // parse validating + parser.parse(new InputSource(new ByteArrayInputStream(docBytes))); + return true; + } + + /** + * Serialize the given DOM node. + * + *

+ * The node will be serialized using the UTF-8 encoding. + *

+ * + * @param node The node to serialize. + * @return String The String representation of the given DOM node. + * @throws TransformerException An error occurred transforming the node to a String. + * @throws IOException An IO error occurred writing the node to a byte array. + */ + public static String serializeNode(final Node node) throws TransformerException, IOException { + return new String(serializeNode(node, "UTF-8", false), "UTF-8"); + } + + + /** + * Serialize the given DOM node. + * + *

+ * The node will be serialized using the UTF-8 encoding. + *

+ * + * @param node The node to serialize. + * @param omitXmlDeclaration The boolean value for omitting the XML Declaration. + * @return String The String representation of the given DOM node. + * @throws TransformerException An error occurred transforming the node to a String. + * @throws IOException An IO error occurred writing the node to a byte array. + */ + public static String serializeNode(final Node node, final boolean omitXmlDeclaration) + throws TransformerException, IOException { + return new String(serializeNode(node, "UTF-8", omitXmlDeclaration), "UTF-8"); + } + + /** + * Serialize the given DOM node. + * + *

+ * The node will be serialized using the UTF-8 encoding. + *

+ * + * @param node The node to serialize. + * @param omitXmlDeclaration The boolean value for omitting the XML Declaration. + * @param lineSeperator Sets the line seperator String of the parser + * @return String The String representation of the given DOM node. + * @throws TransformerException An error occurred transforming the node to a String. + * @throws IOException An IO error occurred writing the node to a byte array. + */ + public static String serializeNode(final Node node, final boolean omitXmlDeclaration, + final String lineSeperator) throws TransformerException, IOException { + return new String(serializeNode(node, "UTF-8", omitXmlDeclaration, lineSeperator), "UTF-8"); + } + + /** + * Serialize the given DOM node to a byte array. + * + * @param node The node to serialize. + * @param xmlEncoding The XML encoding to use. + * @return The serialized node, as a byte array. Using a compatible encoding this can easily be + * converted into a String. + * @throws TransformerException An error occurred transforming the node to a byte array. + * @throws IOException An IO error occurred writing the node to a byte array. + */ + public static byte[] serializeNode(final Node node, final String xmlEncoding) + throws TransformerException, IOException { + return serializeNode(node, xmlEncoding, false); + } + + /** + * Serialize the given DOM node to a byte array. + * + * @param node The node to serialize. + * @param xmlEncoding The XML encoding to use. + * @param omitDeclaration The boolean value for omitting the XML Declaration. + * @return The serialized node, as a byte array. Using a compatible encoding this can easily be + * converted into a String. + * @throws TransformerException An error occurred transforming the node to a byte array. + * @throws IOException An IO error occurred writing the node to a byte array. + */ + public static byte[] serializeNode(final Node node, final String xmlEncoding, + final boolean omitDeclaration) throws TransformerException, IOException { + return serializeNode(node, xmlEncoding, omitDeclaration, null); + } + + + /** + * Serialize the given DOM node to a byte array. + * + * @param node The node to serialize. + * @param xmlEncoding The XML encoding to use. + * @param omitDeclaration The boolean value for omitting the XML Declaration. + * @param lineSeperator Sets the line seperator String of the parser + * @return The serialized node, as a byte array. Using a compatible encoding this can easily be + * converted into a String. + * @throws TransformerException An error occurred transforming the node to a byte array. + * @throws IOException An IO error occurred writing the node to a byte array. + */ + public static byte[] serializeNode(final Node node, final String xmlEncoding, + final boolean omitDeclaration, final String lineSeperator) + throws TransformerException, IOException { + + final TransformerFactory transformerFactory = TransformerFactory.newInstance(); + final Transformer transformer = transformerFactory.newTransformer(); + final ByteArrayOutputStream bos = new ByteArrayOutputStream(16384); + + transformer.setOutputProperty(OutputKeys.METHOD, "xml"); + transformer.setOutputProperty(OutputKeys.ENCODING, xmlEncoding); + final String omit = omitDeclaration ? "yes" : "no"; + transformer.setOutputProperty(OutputKeys.OMIT_XML_DECLARATION, omit); + if (null != lineSeperator) { + transformer.setOutputProperty("{http://xml.apache.org/xalan}line-separator", lineSeperator); + // does not work for xalan <= 2.5.1 + } + transformer.transform(new DOMSource(node), new StreamResult(bos)); + + bos.flush(); + bos.close(); + + return bos.toByteArray(); + } + + /** + * Return the text that a node contains. + * + *

+ * This routine: + *

+ *
    + *
  • Ignores comments and processing instructions.
  • + *
  • Concatenates TEXT nodes, CDATA nodes, and the results recursively processing EntityRef + * nodes.
  • + *
  • Ignores any element nodes in the sublist. (Other possible options are to recurse into + * element sublists or throw an exception.)
  • + *
+ * + * @param node A DOM node from which to extract text. + * @return A String representing its contents. + */ + public static String getText(final Node node) { + if (!node.hasChildNodes()) { + return ""; + } + + final StringBuffer result = new StringBuffer(); + final NodeList list = node.getChildNodes(); + + for (int i = 0; i < list.getLength(); i++) { + final Node subnode = list.item(i); + if (subnode.getNodeType() == Node.TEXT_NODE) { + result.append(subnode.getNodeValue()); + } else if (subnode.getNodeType() == Node.CDATA_SECTION_NODE) { + result.append(subnode.getNodeValue()); + } else if (subnode.getNodeType() == Node.ENTITY_REFERENCE_NODE) { + // Recurse into the subtree for text + // (and ignore comments) + result.append(getText(subnode)); + } + } + return result.toString(); + } + + /** + * Build the namespace prefix to namespace URL mapping in effect for a given node. + * + * @param node The context node for which build the map. + * @return The namespace prefix to namespace URL mapping ( a String value to + * String value mapping). + */ + public static Map getNamespaceDeclarations(Node node) { + final Map nsDecls = new HashMap(); + int i; + + do { + if (node.hasAttributes()) { + final NamedNodeMap attrs = node.getAttributes(); + + for (i = 0; i < attrs.getLength(); i++) { + final Attr attr = (Attr) attrs.item(i); + + // add prefix mapping if none exists + if ("xmlns".equals(attr.getPrefix()) || "xmlns".equals(attr.getName())) { + + final String nsPrefix = attr.getPrefix() != null ? attr.getLocalName() : ""; + + if (nsDecls.get(nsPrefix) == null) { + nsDecls.put(nsPrefix, attr.getValue()); + } + } + } + } + } while ((node = node.getParentNode()) != null); + + return nsDecls; + } + + /** + * Add all namespace declarations declared in the parent(s) of a given element and used in the + * subtree of the given element to the given element. + * + * @param context The element to which to add the namespaces. + */ + public static void localizeNamespaceDeclarations(final Element context) { + final Node parent = context.getParentNode(); + + if (parent != null) { + final Map namespaces = getNamespaceDeclarations(context.getParentNode()); + final Set nsUris = collectNamespaceUris(context); + Iterator iter; + + for (iter = namespaces.entrySet().iterator(); iter.hasNext();) { + final Map.Entry e = (Map.Entry) iter.next(); + + if (nsUris.contains(e.getValue())) { + final String prefix = (String) e.getKey(); + final String nsUri = (String) e.getValue(); + final String nsAttrName = "".equals(prefix) ? "xmlns" : "xmlns:" + prefix; + + context.setAttributeNS(XMLNamespaceConstants.XMLNS_NS_URI, nsAttrName, nsUri); + } + } + } + } + + /** + * Collect all the namespace URIs used in the subtree of a given element. + * + * @param context The element that should be searched for namespace URIs. + * @return All namespace URIs used in the subtree of context, including the ones used + * in context itself. + */ + public static Set collectNamespaceUris(final Element context) { + final Set result = new HashSet(); + + collectNamespaceUrisImpl(context, result); + return result; + } + + /** + * A recursive method to do the work of collectNamespaceURIs. + * + * @param context The context element to evaluate. + * @param result The result, passed as a parameter to avoid unnecessary instantiations of + * Set. + */ + private static void collectNamespaceUrisImpl(final Element context, final Set result) { + final NamedNodeMap attrs = context.getAttributes(); + final NodeList childNodes = context.getChildNodes(); + String nsUri; + int i; + + // add the namespace of the context element + nsUri = context.getNamespaceURI(); + if (nsUri != null && nsUri != XMLNamespaceConstants.XMLNS_NS_URI) { + result.add(nsUri); + } + + // add all namespace URIs from attributes + for (i = 0; i < attrs.getLength(); i++) { + nsUri = attrs.item(i).getNamespaceURI(); + if (nsUri != null && nsUri != XMLNamespaceConstants.XMLNS_NS_URI) { + result.add(nsUri); + } + } + + // add all namespaces from subelements + for (i = 0; i < childNodes.getLength(); i++) { + final Node node = childNodes.item(i); + + if (node.getNodeType() == Node.ELEMENT_NODE) { + collectNamespaceUrisImpl((Element) node, result); + } + } + } + + /** + * Check, that each attribute node in the given NodeList has its parent in the + * NodeList as well. + * + * @param nodes The NodeList to check. + * @return true, if each attribute node in nodes has its parent in + * nodes as well. + */ + public static boolean checkAttributeParentsInNodeList(final NodeList nodes) { + final Set nodeSet = new HashSet(); + int i; + + // put the nodes into the nodeSet + for (i = 0; i < nodes.getLength(); i++) { + nodeSet.add(nodes.item(i)); + } + + // check that each attribute node's parent is in the node list + for (i = 0; i < nodes.getLength(); i++) { + final Node n = nodes.item(i); + + if (n.getNodeType() == Node.ATTRIBUTE_NODE) { + final Attr attr = (Attr) n; + final Element owner = attr.getOwnerElement(); + + if (owner == null) { + if (!isNamespaceDeclaration(attr)) { + return false; + } + } + + if (!nodeSet.contains(owner) && !isNamespaceDeclaration(attr)) { + return false; + } + } + } + + return true; + } + + /** + * Convert an unstructured NodeList into a DocumentFragment. + * + * @param nodeList Contains the node list to be converted into a DOM DocumentFragment. + * @return the resulting DocumentFragment. The DocumentFragment will be backed by a new DOM + * Document, i.e. all noded of the node list will be cloned. + * @throws ParserConfigurationException An error occurred creating the DocumentFragment. + * @precondition The nodes in the node list appear in document order + * @precondition for each Attr node in the node list, the owning Element is in the node list as + * well. + * @precondition each Element or Attr node in the node list is namespace aware. + */ + public static DocumentFragment nodeList2DocumentFragment(final NodeList nodeList) + throws ParserConfigurationException { + + final DocumentBuilder builder = DocumentBuilderFactory.newInstance().newDocumentBuilder(); + final Document doc = builder.newDocument(); + final DocumentFragment result = doc.createDocumentFragment(); + + if (null == nodeList || nodeList.getLength() == 0) { + return result; + } + + int currPos = 0; + currPos = nodeList2DocumentFragment(nodeList, currPos, result, null, null) + 1; + + while (currPos < nodeList.getLength()) { + currPos = nodeList2DocumentFragment(nodeList, currPos, result, null, null) + 1; + } + return result; + } + + /** + * Helper method for the nodeList2DocumentFragment. + * + * @param nodeList The NodeList to convert. + * @param currPos The current position in the nodeList. + * @param result The resulting DocumentFragment. + * @param currOrgElem The current original element. + * @param currClonedElem The current cloned element. + * @return The current position. + */ + private static int nodeList2DocumentFragment(final NodeList nodeList, int currPos, + final DocumentFragment result, Element currOrgElem, Element currClonedElem) { + + while (currPos < nodeList.getLength()) { + final Node currentNode = nodeList.item(currPos); + switch (currentNode.getNodeType()) { + case Node.COMMENT_NODE: + case Node.PROCESSING_INSTRUCTION_NODE: + case Node.TEXT_NODE: { + // Append current node either to resulting DocumentFragment or to + // current cloned Element + if (null == currClonedElem) { + result.appendChild(result.getOwnerDocument().importNode(currentNode, false)); + } else { + // Stop processing if current Node is not a descendant of + // current Element + if (!isAncestor(currOrgElem, currentNode)) { + return --currPos; + } + + currClonedElem.appendChild(result.getOwnerDocument().importNode(currentNode, false)); + } + break; + } + + case Node.ELEMENT_NODE: { + final Element nextCurrOrgElem = (Element) currentNode; + final Element nextCurrClonedElem = result.getOwnerDocument() + .createElementNS(nextCurrOrgElem.getNamespaceURI(), nextCurrOrgElem.getNodeName()); + + // Append current Node either to resulting DocumentFragment or to + // current cloned Element + if (null == currClonedElem) { + result.appendChild(nextCurrClonedElem); + currOrgElem = nextCurrOrgElem; + currClonedElem = nextCurrClonedElem; + } else { + // Stop processing if current Node is not a descendant of + // current Element + if (!isAncestor(currOrgElem, currentNode)) { + return --currPos; + } + + currClonedElem.appendChild(nextCurrClonedElem); + } + + // Process current Node (of type Element) recursively + currPos = nodeList2DocumentFragment(nodeList, ++currPos, result, nextCurrOrgElem, + nextCurrClonedElem); + + break; + } + + case Node.ATTRIBUTE_NODE: { + final Attr currAttr = (Attr) currentNode; + + // GK 20030411: Hack to overcome problems with IAIK IXSIL + if (currAttr.getOwnerElement() == null) { + break; + } + if (currClonedElem == null) { + break; + } + + // currClonedElem must be the owner Element of currAttr if + // preconditions are met + currClonedElem.setAttributeNS(currAttr.getNamespaceURI(), currAttr.getNodeName(), + currAttr.getValue()); + break; + } + + default: { + // All other nodes will be ignored + } + } + + currPos++; + } + + return currPos; + } + + /** + * Check, if the given attribute is a namespace declaration. + * + * @param attr The attribute to check. + * @return true, if the attribute is a namespace declaration, false + * otherwise. + */ + private static boolean isNamespaceDeclaration(final Attr attr) { + return XMLNamespaceConstants.XMLNS_NS_URI.equals(attr.getNamespaceURI()); + } + + /** + * Check, if a given DOM element is an ancestor of a given node. + * + * @param candAnc The DOM element to check for being the ancestor. + * @param cand The node to check for being the child. + * @return true, if candAnc is an (indirect) ancestor of + * cand; false otherwise. + */ + public static boolean isAncestor(final Element candAnc, final Node cand) { + Node currPar = cand.getParentNode(); + + while (currPar != null) { + if (candAnc == currPar) { + return true; + } + currPar = currPar.getParentNode(); + } + return false; + } + + /** + * Selects the (first) element from a node list and returns it. + * + * @param nl The NodeList to get the element from. + * @return The (first) element included in the node list or null if the node list is + * null or empty or no element is included in the list. + */ + public static Element getElementFromNodeList(final NodeList nl) { + if ((nl == null) || (nl.getLength() == 0)) { + return null; + } + for (int i = 0; i < nl.getLength(); i++) { + final Node node = nl.item(i); + if (node.getNodeType() == Node.ELEMENT_NODE) { + return (Element) node; + } + } + return null; + } + + /** + * Returns all child elements of the given element. + * + * @param parent The element to get the child elements from. + * + * @return A list including all child elements of the given element. Maybe empty if the parent + * element has no child elements. + */ + public static List getChildElements(final Element parent) { + final Vector v = new Vector(); + final NodeList nl = parent.getChildNodes(); + final int length = nl.getLength(); + for (int i = 0; i < length; i++) { + final Node node = nl.item(i); + if (node.getNodeType() == Node.ELEMENT_NODE) { + v.add(node); + } + } + return v; + } + + /** + * Returns a byte array from given node. + * + * @param node Element node + * @return transformed node + * @throws TransformerException in case of an error + */ + public static byte[] nodeToByteArray(final Node node) throws TransformerException { + final Source source = new DOMSource(node); + final ByteArrayOutputStream out = new ByteArrayOutputStream(); + // StringWriter stringWriter = new StringWriter(); + final Result result = new StreamResult(out); + final TransformerFactory factory = TransformerFactory.newInstance(); + final Transformer transformer = factory.newTransformer(); + transformer.transform(source, result); + return out.toByteArray(); + } + + +} diff --git a/eaaf_core/src/main/java/at/gv/egiz/eaaf/core/impl/utils/EAAFDomEntityResolver.java b/eaaf_core/src/main/java/at/gv/egiz/eaaf/core/impl/utils/EAAFDomEntityResolver.java deleted file mode 100644 index 5be0a475..00000000 --- a/eaaf_core/src/main/java/at/gv/egiz/eaaf/core/impl/utils/EAAFDomEntityResolver.java +++ /dev/null @@ -1,128 +0,0 @@ -/******************************************************************************* - * Copyright 2017 Graz University of Technology - * EAAF-Core Components has been developed in a cooperation between EGIZ, - * A-SIT Plus, A-SIT, and Graz University of Technology. - * - * Licensed under the EUPL, Version 1.2 or - as soon they will be approved by - * the European Commission - subsequent versions of the EUPL (the "Licence"); - * You may not use this work except in compliance with the Licence. - * You may obtain a copy of the Licence at: - * https://joinup.ec.europa.eu/news/understanding-eupl-v12 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the Licence is distributed on an "AS IS" basis, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the Licence for the specific language governing permissions and - * limitations under the Licence. - * - * This product combines work with different licenses. See the "NOTICE" text - * file for details on the various modules and licenses. - * The "NOTICE" text file is part of the distribution. Any derivative works - * that you distribute must include a readable copy of the "NOTICE" text file. - *******************************************************************************/ -/******************************************************************************* - *******************************************************************************/ -/******************************************************************************* - *******************************************************************************/ - - -package at.gv.egiz.eaaf.core.impl.utils; - -import java.io.InputStream; - -import org.apache.xerces.util.URI; -import org.apache.xerces.util.URI.MalformedURIException; -import org.slf4j.Logger; -import org.slf4j.LoggerFactory; -import org.xml.sax.EntityResolver; -import org.xml.sax.InputSource; - -import at.gv.egiz.eaaf.core.api.data.XMLNamespaceConstants; - -/** - * An EntityResolver that looks up entities stored as - * local resources. - * - *

The following DTDs are mapped to local resources: - *

    - *
  • The XMLSchema.dtd
  • - *
  • The datatypes.dtd
  • - *
- *

- *

For all other resources, an attempt is made to resolve them as resources, - * either absolute or relative to Constants.SCHEMA_ROOT. - * - */ -public class EAAFDomEntityResolver implements EntityResolver { - private static final Logger log = LoggerFactory.getLogger(EAAFDomEntityResolver.class); - - /** - * Resolve an entity. - * - * The systemId parameter is used to perform the lookup of the - * entity as a resource, either by interpreting the systemId as - * an absolute resource path, or by appending the last path component of - * systemId to Constants.SCHEMA_ROOT. - * - * @param publicId The public ID of the resource. - * @param systemId The system ID of the resource. - * @return An InputSource from which the entity can be read, or - * null, if the entity could not be found. - * @see org.xml.sax.EntityResolver#resolveEntity(java.lang.String, java.lang.String) - */ - public InputSource resolveEntity(String publicId, String systemId) { - InputStream stream; - int slashPos; - - if (publicId != null) { - // check if we can resolve some standard dtd's - if (publicId.equalsIgnoreCase("-//W3C//DTD XMLSchema 200102//EN")) { - return new InputSource( - getClass().getResourceAsStream( - XMLNamespaceConstants.SCHEMA_ROOT + "XMLSchema.dtd")); - } else if (publicId.equalsIgnoreCase("datatypes")) { - return new InputSource( - getClass().getResourceAsStream( - XMLNamespaceConstants.SCHEMA_ROOT + "datatypes.dtd")); - } - } else if (systemId != null) { - // get the URI path - try { - URI uri = new URI(systemId); - systemId = uri.getPath(); - - if (!"file".equals(uri.getScheme()) || "".equals(systemId.trim())) { - return null; - } - - } catch (MalformedURIException e) { - return null; - } - - // try to get the resource from the full path - stream = getClass().getResourceAsStream(systemId); - if (stream != null) { - InputSource source = new InputSource(stream); - - source.setSystemId(systemId); - return source; - } - - // try to get the resource from the last path component - slashPos = systemId.lastIndexOf('/'); - if (slashPos >= 0 && systemId.length() > slashPos) { - systemId = systemId.substring(slashPos + 1, systemId.length()); - stream = - getClass().getResourceAsStream(XMLNamespaceConstants.SCHEMA_ROOT + systemId); - if (stream != null) { - InputSource source = new InputSource(stream); - - source.setSystemId(systemId); - return source; - } - } - } - - return null; // nothing found - let the parser handle the entity - } -} \ No newline at end of file diff --git a/eaaf_core/src/main/java/at/gv/egiz/eaaf/core/impl/utils/EaafDomEntityResolver.java b/eaaf_core/src/main/java/at/gv/egiz/eaaf/core/impl/utils/EaafDomEntityResolver.java new file mode 100644 index 00000000..c2700214 --- /dev/null +++ b/eaaf_core/src/main/java/at/gv/egiz/eaaf/core/impl/utils/EaafDomEntityResolver.java @@ -0,0 +1,118 @@ +/* + * Copyright 2017 Graz University of Technology EAAF-Core Components has been developed in a + * cooperation between EGIZ, A-SIT Plus, A-SIT, and Graz University of Technology. + * + * Licensed under the EUPL, Version 1.2 or - as soon they will be approved by the European + * Commission - subsequent versions of the EUPL (the "Licence"); You may not use this work except in + * compliance with the Licence. You may obtain a copy of the Licence at: + * https://joinup.ec.europa.eu/news/understanding-eupl-v12 + * + * Unless required by applicable law or agreed to in writing, software distributed under the Licence + * is distributed on an "AS IS" basis, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express + * or implied. See the Licence for the specific language governing permissions and limitations under + * the Licence. + * + * This product combines work with different licenses. See the "NOTICE" text file for details on the + * various modules and licenses. The "NOTICE" text file is part of the distribution. Any derivative + * works that you distribute must include a readable copy of the "NOTICE" text file. +*/ + + + +package at.gv.egiz.eaaf.core.impl.utils; + +import java.io.InputStream; +import at.gv.egiz.eaaf.core.api.data.XMLNamespaceConstants; +import org.apache.xerces.util.URI; +import org.apache.xerces.util.URI.MalformedURIException; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; +import org.xml.sax.EntityResolver; +import org.xml.sax.InputSource; + +/** + * An EntityResolver that looks up entities stored as local resources. + * + *

+ * The following DTDs are mapped to local resources: + *

    + *
  • The XMLSchema.dtd
  • + *
  • The datatypes.dtd
  • + *
+ *

+ *

+ * For all other resources, an attempt is made to resolve them as resources, either absolute or + * relative to Constants.SCHEMA_ROOT. + * + */ +public class EaafDomEntityResolver implements EntityResolver { + private static final Logger log = LoggerFactory.getLogger(EaafDomEntityResolver.class); + + /** + * Resolve an entity. + *

+ * The systemId parameter is used to perform the lookup of the entity as a resource, + * either by interpreting the systemId as an absolute resource path, or by appending + * the last path component of systemId to Constants.SCHEMA_ROOT. + *

+ * + * @param publicId The public ID of the resource. + * @param systemId The system ID of the resource. + * @return An InputSource from which the entity can be read, or null, if + * the entity could not be found. + * @see org.xml.sax.EntityResolver#resolveEntity(java.lang.String, java.lang.String) + */ + @Override + public InputSource resolveEntity(final String publicId, String systemId) { + InputStream stream; + int slashPos; + + if (publicId != null) { + // check if we can resolve some standard dtd's + if (publicId.equalsIgnoreCase("-//W3C//DTD XMLSchema 200102//EN")) { + return new InputSource( + getClass().getResourceAsStream(XMLNamespaceConstants.SCHEMA_ROOT + "XMLSchema.dtd")); + } else if (publicId.equalsIgnoreCase("datatypes")) { + return new InputSource( + getClass().getResourceAsStream(XMLNamespaceConstants.SCHEMA_ROOT + "datatypes.dtd")); + } + } else if (systemId != null) { + // get the URI path + try { + final URI uri = new URI(systemId); + systemId = uri.getPath(); + + if (!"file".equals(uri.getScheme()) || "".equals(systemId.trim())) { + return null; + } + + } catch (final MalformedURIException e) { + return null; + } + + // try to get the resource from the full path + stream = getClass().getResourceAsStream(systemId); + if (stream != null) { + final InputSource source = new InputSource(stream); + + source.setSystemId(systemId); + return source; + } + + // try to get the resource from the last path component + slashPos = systemId.lastIndexOf('/'); + if (slashPos >= 0 && systemId.length() > slashPos) { + systemId = systemId.substring(slashPos + 1, systemId.length()); + stream = getClass().getResourceAsStream(XMLNamespaceConstants.SCHEMA_ROOT + systemId); + if (stream != null) { + final InputSource source = new InputSource(stream); + + source.setSystemId(systemId); + return source; + } + } + } + + return null; // nothing found - let the parser handle the entity + } +} diff --git a/eaaf_core/src/main/java/at/gv/egiz/eaaf/core/impl/utils/XPathUtils.java b/eaaf_core/src/main/java/at/gv/egiz/eaaf/core/impl/utils/XPathUtils.java index c50b9e08..d6745c78 100644 --- a/eaaf_core/src/main/java/at/gv/egiz/eaaf/core/impl/utils/XPathUtils.java +++ b/eaaf_core/src/main/java/at/gv/egiz/eaaf/core/impl/utils/XPathUtils.java @@ -1,36 +1,30 @@ -/******************************************************************************* - * Copyright 2017 Graz University of Technology - * EAAF-Core Components has been developed in a cooperation between EGIZ, - * A-SIT Plus, A-SIT, and Graz University of Technology. +/* + * Copyright 2017 Graz University of Technology EAAF-Core Components has been developed in a + * cooperation between EGIZ, A-SIT Plus, A-SIT, and Graz University of Technology. * - * Licensed under the EUPL, Version 1.2 or - as soon they will be approved by - * the European Commission - subsequent versions of the EUPL (the "Licence"); - * You may not use this work except in compliance with the Licence. - * You may obtain a copy of the Licence at: + * Licensed under the EUPL, Version 1.2 or - as soon they will be approved by the European + * Commission - subsequent versions of the EUPL (the "Licence"); You may not use this work except in + * compliance with the Licence. You may obtain a copy of the Licence at: * https://joinup.ec.europa.eu/news/understanding-eupl-v12 * - * Unless required by applicable law or agreed to in writing, software - * distributed under the Licence is distributed on an "AS IS" basis, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the Licence for the specific language governing permissions and - * limitations under the Licence. - * - * This product combines work with different licenses. See the "NOTICE" text - * file for details on the various modules and licenses. - * The "NOTICE" text file is part of the distribution. Any derivative works - * that you distribute must include a readable copy of the "NOTICE" text file. - *******************************************************************************/ -/******************************************************************************* - *******************************************************************************/ -/******************************************************************************* - *******************************************************************************/ + * Unless required by applicable law or agreed to in writing, software distributed under the Licence + * is distributed on an "AS IS" basis, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express + * or implied. See the Licence for the specific language governing permissions and limitations under + * the Licence. + * + * This product combines work with different licenses. See the "NOTICE" text file for details on the + * various modules and licenses. The "NOTICE" text file is part of the distribution. Any derivative + * works that you distribute must include a readable copy of the "NOTICE" text file. +*/ + package at.gv.egiz.eaaf.core.impl.utils; import java.util.List; import java.util.Map; - +import at.gv.egiz.eaaf.core.api.data.XMLNamespaceConstants; +import at.gv.egiz.eaaf.core.exceptions.XPathException; import org.jaxen.JaxenException; import org.jaxen.NamespaceContext; import org.jaxen.Navigator; @@ -43,35 +37,31 @@ import org.w3c.dom.Node; import org.w3c.dom.NodeList; import org.w3c.dom.traversal.NodeIterator; -import at.gv.egiz.eaaf.core.api.data.XMLNamespaceConstants; -import at.gv.egiz.eaaf.core.exceptions.XPathException; - /** * Utility methods to evaluate XPath expressions on DOM nodes. - * + * * @author Patrick Peck * @version $Id$ */ public class XPathUtils { /** - * The XPath expression selecting all nodes under a given root (including the - * root node itself). + * The XPath expression selecting all nodes under a given root (including the root node itself). */ - public static final String ALL_NODES_XPATH = - "(.//. | .//@* | .//namespace::*)"; + public static final String ALL_NODES_XPATH = "(.//. | .//@* | .//namespace::*)"; /** The DocumentNavigator to use for navigating the document. */ - private static Navigator documentNavigator = - DocumentNavigator.getInstance(); + private static Navigator documentNavigator = DocumentNavigator.getInstance(); /** The default namespace prefix to namespace URI mappings. */ private static NamespaceContext NS_CONTEXT; - - static { - SimpleNamespaceContext ctx = new SimpleNamespaceContext(); + + static { + final SimpleNamespaceContext ctx = new SimpleNamespaceContext(); ctx.addNamespace(XMLNamespaceConstants.MOA_PREFIX, XMLNamespaceConstants.MOA_NS_URI); - ctx.addNamespace(XMLNamespaceConstants.MOA_CONFIG_PREFIX, XMLNamespaceConstants.MOA_CONFIG_NS_URI); - ctx.addNamespace(XMLNamespaceConstants.MOA_ID_CONFIG_PREFIX, XMLNamespaceConstants.MOA_ID_CONFIG_NS_URI); + ctx.addNamespace(XMLNamespaceConstants.MOA_CONFIG_PREFIX, + XMLNamespaceConstants.MOA_CONFIG_NS_URI); + ctx.addNamespace(XMLNamespaceConstants.MOA_ID_CONFIG_PREFIX, + XMLNamespaceConstants.MOA_ID_CONFIG_NS_URI); ctx.addNamespace(XMLNamespaceConstants.SL10_PREFIX, XMLNamespaceConstants.SL10_NS_URI); ctx.addNamespace(XMLNamespaceConstants.SL11_PREFIX, XMLNamespaceConstants.SL11_NS_URI); ctx.addNamespace(XMLNamespaceConstants.SL12_PREFIX, XMLNamespaceConstants.SL12_NS_URI); @@ -82,7 +72,8 @@ public class XPathUtils { ctx.addNamespace(XMLNamespaceConstants.DSIG_PREFIX, XMLNamespaceConstants.DSIG_NS_URI); ctx.addNamespace(XMLNamespaceConstants.XSLT_PREFIX, XMLNamespaceConstants.XSLT_NS_URI); ctx.addNamespace(XMLNamespaceConstants.XSI_PREFIX, XMLNamespaceConstants.XSI_NS_URI); - ctx.addNamespace(XMLNamespaceConstants.DSIG_FILTER2_PREFIX, XMLNamespaceConstants.DSIG_FILTER2_NS_URI); + ctx.addNamespace(XMLNamespaceConstants.DSIG_FILTER2_PREFIX, + XMLNamespaceConstants.DSIG_FILTER2_NS_URI); ctx.addNamespace(XMLNamespaceConstants.DSIG_EC_PREFIX, XMLNamespaceConstants.DSIG_EC_NS_URI); ctx.addNamespace(XMLNamespaceConstants.MD_PREFIX, XMLNamespaceConstants.MD_NS_URI); ctx.addNamespace(XMLNamespaceConstants.MDP_PREFIX, XMLNamespaceConstants.MDP_NS_URI); @@ -94,452 +85,398 @@ public class XPathUtils { ctx.addNamespace(XMLNamespaceConstants.SAML2_PREFIX, XMLNamespaceConstants.SAML2_NS_URI); ctx.addNamespace(XMLNamespaceConstants.SAML2P_PREFIX, XMLNamespaceConstants.SAML2P_NS_URI); ctx.addNamespace(XMLNamespaceConstants.XENC_PREFIX, XMLNamespaceConstants.XENC_NS_URI); - ctx.addNamespace(XMLNamespaceConstants.XADES_1_1_1_NS_PREFIX, XMLNamespaceConstants.XADES_1_1_1_NS_URI); + ctx.addNamespace(XMLNamespaceConstants.XADES_1_1_1_NS_PREFIX, + XMLNamespaceConstants.XADES_1_1_1_NS_URI); NS_CONTEXT = ctx; } /** - * Return a NodeIterator over the nodes matching the XPath - * expression. - * - * All namespace URIs and prefixes declared in the Constants - * interface are used for resolving namespaces. - * - * @param contextNode The root node from which to evaluate the XPath - * expression. + * Return a NodeIterator over the nodes matching the XPath expression. + * + *

+ * All namespace URIs and prefixes declared in the Constants interface are used for + * resolving namespaces. + *

+ * + * @param contextNode The root node from which to evaluate the XPath expression. * @param exp The XPath expression to evaluate. * @return An iterator over the resulting nodes. * @throws XPathException An error occurred evaluating the XPath expression. */ - public static NodeIterator selectNodeIterator(Node contextNode, String exp) - throws XPathException { + public static NodeIterator selectNodeIterator(final Node contextNode, final String exp) + throws XPathException { return selectNodeIterator(contextNode, NS_CONTEXT, exp); } /** - * Return a NodeIterator over the nodes matching the XPath - * expression. - * - * @param contextNode The root node from which to evaluate the XPath - * expression. - * @param namespaceElement An element from which to build the - * namespace mapping for evaluating the XPath expression + * Return a NodeIterator over the nodes matching the XPath expression. + * + * @param contextNode The root node from which to evaluate the XPath expression. + * @param namespaceElement An element from which to build the namespace mapping for evaluating the + * XPath expression * @param exp The XPath expression to evaluate. * @return An iterator over the resulting nodes. * @throws XPathException An error occurred evaluating the XPath expression. */ - public static NodeIterator selectNodeIterator( - Node contextNode, - Element namespaceElement, - String exp) - throws XPathException { + public static NodeIterator selectNodeIterator(final Node contextNode, + final Element namespaceElement, final String exp) throws XPathException { try { - SimpleNamespaceContext ctx = new SimpleNamespaceContext(); + final SimpleNamespaceContext ctx = new SimpleNamespaceContext(); ctx.addElementNamespaces(documentNavigator, namespaceElement); return selectNodeIterator(contextNode, ctx, exp); - - } catch (JaxenException e) { - throw new XPathException("XPath operation FAILED. Reason: " + e.getMessage(), e); - + + } catch (final JaxenException e) { + throw new XPathException("XPath operation FAILED. Reason: " + e.getMessage(), e); + } } /** - * Return a NodeIterator over the nodes matching the XPath - * expression. - * - * @param contextNode The root node from which to evaluate the XPath - * expression. - * @param namespaceMapping A namespace prefix to namespace URI mapping - * (String to String) for evaluating the XPath - * expression. + * Return a NodeIterator over the nodes matching the XPath expression. + * + * @param contextNode The root node from which to evaluate the XPath expression. + * @param namespaceMapping A namespace prefix to namespace URI mapping (String to + * String) for evaluating the XPath expression. * @param exp The XPath expression to evaluate. * @return An iterator over the resulting nodes. * @throws XPathException An error occurred evaluating the XPath expression. */ - public static NodeIterator selectNodeIterator( - Node contextNode, - Map namespaceMapping, - String exp) - throws XPathException { + public static NodeIterator selectNodeIterator(final Node contextNode, final Map namespaceMapping, + final String exp) throws XPathException { - SimpleNamespaceContext ctx = new SimpleNamespaceContext(namespaceMapping); + final SimpleNamespaceContext ctx = new SimpleNamespaceContext(namespaceMapping); return selectNodeIterator(contextNode, ctx, exp); } /** - * Return a NodeIterator over the nodes matching the XPath - * expression. - * - * @param contextNode The root node from which to evaluate the XPath - * expression. - * @param nsContext The NamespaceContext for resolving namespace - * prefixes to namespace URIs for evaluating the XPath expression. + * Return a NodeIterator over the nodes matching the XPath expression. + * + * @param contextNode The root node from which to evaluate the XPath expression. + * @param nsContext The NamespaceContext for resolving namespace prefixes to + * namespace URIs for evaluating the XPath expression. * @param exp The XPath expression to evaluate. * @return An iterator over the resulting nodes. * @throws XPathException An error occurred evaluating the XPath expression. */ - private static NodeIterator selectNodeIterator( - Node contextNode, - NamespaceContext nsContext, - String exp) - throws XPathException { + private static NodeIterator selectNodeIterator(final Node contextNode, + final NamespaceContext nsContext, final String exp) throws XPathException { try { - DOMXPath xpath = new DOMXPath(exp); + final DOMXPath xpath = new DOMXPath(exp); List nodes; xpath.setNamespaceContext(nsContext); nodes = xpath.selectNodes(contextNode); return new NodeIteratorAdapter(nodes.listIterator()); - - } catch (JaxenException e) { - throw new XPathException("XPath operation FAILED. Reason: " + e.getMessage(), e); - + + } catch (final JaxenException e) { + throw new XPathException("XPath operation FAILED. Reason: " + e.getMessage(), e); + } } /** - * Return a NodeList of all the nodes matching the XPath - * expression. - * - * All namespace URIs and prefixes declared in the Constants - * interface are used for resolving namespaces. - * - * @param contextNode The root node from which to evaluate the XPath - * expression. + * Return a NodeList of all the nodes matching the XPath expression. + *

+ * All namespace URIs and prefixes declared in the Constants interface are used for + * resolving namespaces. + *

+ * @param contextNode The root node from which to evaluate the XPath expression. * @param exp The XPath expression to evaluate. * @return A NodeList containing the matching nodes. * @throws XPathException An error occurred evaluating the XPath expression. */ - public static NodeList selectNodeList(Node contextNode, String exp) - throws XPathException { + public static NodeList selectNodeList(final Node contextNode, final String exp) + throws XPathException { return selectNodeList(contextNode, NS_CONTEXT, exp); } /** - * Return a NodeList of all the nodes matching the XPath - * expression. - * - * @param contextNode The root node from which to evaluate the XPath - * expression. - * @param namespaceElement An element from which to build the - * namespace mapping for evaluating the XPath expression + * Return a NodeList of all the nodes matching the XPath expression. + * + * @param contextNode The root node from which to evaluate the XPath expression. + * @param namespaceElement An element from which to build the namespace mapping for evaluating the + * XPath expression * @param exp The XPath expression to evaluate. * @return A NodeList containing the matching nodes. * @throws XPathException An error occurred evaluating the XPath expression. */ - public static NodeList selectNodeList( - Node contextNode, - Element namespaceElement, - String exp) - throws XPathException { + public static NodeList selectNodeList(final Node contextNode, final Element namespaceElement, + final String exp) throws XPathException { try { - SimpleNamespaceContext ctx = new SimpleNamespaceContext(); + final SimpleNamespaceContext ctx = new SimpleNamespaceContext(); ctx.addElementNamespaces(documentNavigator, namespaceElement); return selectNodeList(contextNode, ctx, exp); - - } catch (JaxenException e) { - throw new XPathException("XPath operation FAILED. Reason: " + e.getMessage(), e); - + + } catch (final JaxenException e) { + throw new XPathException("XPath operation FAILED. Reason: " + e.getMessage(), e); + } } /** - * Return a NodeList of all the nodes matching the XPath - * expression. - * - * @param contextNode The root node from which to evaluate the XPath - * expression. - * @param namespaceMapping A namespace prefix to namespace URI mapping - * (String to String) for evaluating the XPath - * expression. + * Return a NodeList of all the nodes matching the XPath expression. + * + * @param contextNode The root node from which to evaluate the XPath expression. + * @param namespaceMapping A namespace prefix to namespace URI mapping (String to + * String) for evaluating the XPath expression. * @param exp The XPath expression to evaluate. * @return A NodeList containing the matching nodes. * @throws XPathException An error occurred evaluating the XPath expression. */ - public static NodeList selectNodeList( - Node contextNode, - Map namespaceMapping, - String exp) - throws XPathException { + public static NodeList selectNodeList(final Node contextNode, final Map namespaceMapping, + final String exp) throws XPathException { - SimpleNamespaceContext ctx = new SimpleNamespaceContext(namespaceMapping); + final SimpleNamespaceContext ctx = new SimpleNamespaceContext(namespaceMapping); return selectNodeList(contextNode, ctx, exp); } /** - * Return a NodeList of all the nodes matching the XPath - * expression. - * - * @param contextNode The root node from which to evaluate the XPath - * expression. - * @param nsContext The NamespaceContext for resolving namespace - * prefixes to namespace URIs for evaluating the XPath expression. + * Return a NodeList of all the nodes matching the XPath expression. + * + * @param contextNode The root node from which to evaluate the XPath expression. + * @param nsContext The NamespaceContext for resolving namespace prefixes to + * namespace URIs for evaluating the XPath expression. * @param exp The XPath expression to evaluate. * @return A NodeList containing the matching nodes. * @throws XPathException An error occurred evaluating the XPath expression. */ - private static NodeList selectNodeList(Node contextNode, NamespaceContext nsContext, String exp) throws XPathException { - try { - DOMXPath xpath = new DOMXPath(exp); - List nodes; - xpath.setNamespaceContext(nsContext); - nodes = xpath.selectNodes(contextNode); - return new NodeListAdapter(nodes); - - } catch (JaxenException e) { - throw new XPathException("XPath operation FAILED. Reason: " + e.getMessage(), e); - - } + private static NodeList selectNodeList(final Node contextNode, final NamespaceContext nsContext, + final String exp) throws XPathException { + try { + final DOMXPath xpath = new DOMXPath(exp); + List nodes; + xpath.setNamespaceContext(nsContext); + nodes = xpath.selectNodes(contextNode); + return new NodeListAdapter(nodes); + + } catch (final JaxenException e) { + throw new XPathException("XPath operation FAILED. Reason: " + e.getMessage(), e); + + } } /** * Select the first node matching an XPath expression. - * - * All namespace URIs and prefixes declared in the Constants - * interface are used for resolving namespaces. - * - * @param contextNode The root node from which to evaluate the XPath - * expression. + *

+ * All namespace URIs and prefixes declared in the Constants interface are used for + * resolving namespaces. + *

+ * @param contextNode The root node from which to evaluate the XPath expression. * @param exp The XPath expression to evaluate. - * @return Node The first node matching the XPath expression, or - * null, if no node matched. + * @return Node The first node matching the XPath expression, or null, if no node + * matched. * @throws XPathException An error occurred evaluating the XPath expression. */ - public static Node selectSingleNode(Node contextNode, String exp) - throws XPathException { + public static Node selectSingleNode(final Node contextNode, final String exp) + throws XPathException { return selectSingleNode(contextNode, NS_CONTEXT, exp); } /** * Select the first node matching an XPath expression. - * - * @param contextNode The root node from which to evaluate the XPath - * expression. - * @param namespaceElement An element from which to build the - * namespace mapping for evaluating the XPath expression + * + * @param contextNode The root node from which to evaluate the XPath expression. + * @param namespaceElement An element from which to build the namespace mapping for evaluating the + * XPath expression * @param exp The XPath expression to evaluate. - * @return Node The first node matching the XPath expression, or - * null, if no node matched. + * @return Node The first node matching the XPath expression, or null, if no node + * matched. * @throws XPathException An error occurred evaluating the XPath expression. */ - public static Node selectSingleNode( - Node contextNode, - Element namespaceElement, - String exp) - throws XPathException { + public static Node selectSingleNode(final Node contextNode, final Element namespaceElement, + final String exp) throws XPathException { try { - SimpleNamespaceContext ctx = new SimpleNamespaceContext(); + final SimpleNamespaceContext ctx = new SimpleNamespaceContext(); ctx.addElementNamespaces(documentNavigator, namespaceElement); return selectSingleNode(contextNode, ctx, exp); - - } catch (JaxenException e) { - throw new XPathException("XPath operation FAILED. Reason: " + e.getMessage(), e); - + + } catch (final JaxenException e) { + throw new XPathException("XPath operation FAILED. Reason: " + e.getMessage(), e); + } } /** * Select the first node matching an XPath expression. - * - * @param contextNode The root node from which to evaluate the XPath - * expression. - * @param namespaceMapping A namespace prefix to namespace URI mapping - * (String to String) for evaluating the XPath - * expression. + * + * @param contextNode The root node from which to evaluate the XPath expression. + * @param namespaceMapping A namespace prefix to namespace URI mapping (String to + * String) for evaluating the XPath expression. * @param exp The XPath expression to evaluate. - * @return Node The first node matching the XPath expression, or - * null, if no node matched. + * @return Node The first node matching the XPath expression, or null, if no node + * matched. * @throws XPathException An error occurred evaluating the XPath expression. */ - public static Node selectSingleNode( - Node contextNode, - Map namespaceMapping, - String exp) - throws XPathException { + public static Node selectSingleNode(final Node contextNode, final Map namespaceMapping, + final String exp) throws XPathException { - SimpleNamespaceContext ctx = new SimpleNamespaceContext(namespaceMapping); + final SimpleNamespaceContext ctx = new SimpleNamespaceContext(namespaceMapping); return selectSingleNode(contextNode, ctx, exp); } /** * Select the first node matching an XPath expression. - * - * @param contextNode The root node from which to evaluate the XPath - * expression. - * @param nsContext The NamespaceContext for resolving namespace - * prefixes to namespace URIs for evaluating the XPath expression. + * + * @param contextNode The root node from which to evaluate the XPath expression. + * @param nsContext The NamespaceContext for resolving namespace prefixes to + * namespace URIs for evaluating the XPath expression. * @param exp The XPath expression to evaluate. - * @return Node The first node matching the XPath expression, or - * null, if no node matched. + * @return Node The first node matching the XPath expression, or null, if no node + * matched. * @throws XPathException An error occurred evaluating the XPath expression. */ - public static Node selectSingleNode( - Node contextNode, - NamespaceContext nsContext, - String exp) - throws XPathException { + public static Node selectSingleNode(final Node contextNode, final NamespaceContext nsContext, + final String exp) throws XPathException { try { - DOMXPath xpath = new DOMXPath(exp); + final DOMXPath xpath = new DOMXPath(exp); xpath.setNamespaceContext(nsContext); return (Node) xpath.selectSingleNode(contextNode); - - } catch (JaxenException e) { - throw new XPathException("XPath operation FAILED. Reason: " + e.getMessage(), e); - + + } catch (final JaxenException e) { + throw new XPathException("XPath operation FAILED. Reason: " + e.getMessage(), e); + } } /** - * Return the value of a DOM element whose location is given by an XPath - * expression. - * + * Return the value of a DOM element whose location is given by an XPath expression. + * * @param root The root element from which to evaluate the XPath. - * @param xpath The XPath expression pointing to the element whose value - * to return. - * @param def The default value to return, if no element can be found using - * the given xpath. - * @return The element value, if it can be located using the - * xpath. Otherwise, def is returned. + * @param xpath The XPath expression pointing to the element whose value to return. + * @param def The default value to return, if no element can be found using the given + * xpath. + * @return The element value, if it can be located using the xpath. Otherwise, + * def is returned. */ - public static String getElementValue( - Element root, - String xpath, - String def) { + public static String getElementValue(final Element root, final String xpath, final String def) { - Element elem = (Element) XPathUtils.selectSingleNode(root, xpath); - return elem != null ? DOMUtils.getText(elem) : def; + final Element elem = (Element) XPathUtils.selectSingleNode(root, xpath); + return elem != null ? DomUtils.getText(elem) : def; } /** - * Return the value of a DOM attribute whose location is given by an XPath - * expression. - * + * Return the value of a DOM attribute whose location is given by an XPath expression. + * * @param root The root element from which to evaluate the XPath. - * @param xpath The XPath expression pointing to the attribute whose value to - * return. - * @param def The default value to return, if no attribute can be found using - * the given xpath. - * @return The element value, if it can be located using the - * xpath. Otherwise, def is returned. + * @param xpath The XPath expression pointing to the attribute whose value to return. + * @param def The default value to return, if no attribute can be found using the given + * xpath. + * @return The element value, if it can be located using the xpath. Otherwise, + * def is returned. */ - public static String getAttributeValue( - Element root, - String xpath, - String def) { + public static String getAttributeValue(final Element root, final String xpath, final String def) { - Attr attr = (Attr) XPathUtils.selectSingleNode(root, xpath); + final Attr attr = (Attr) XPathUtils.selectSingleNode(root, xpath); return attr != null ? attr.getValue() : def; } - + /** - * Returns the namespace prefix used within XPathUtils for referring to - * the namespace of the specified (Security Layer command) element. - * - * This namespace prefix can be used in various XPath expression evaluation methods - * within XPathUtils without explicitely binding it to the particular - * namespace. - * - * @param contextElement The (Security Layer command) element. - * - * @return the namespace prefix used within XPathUtils for referring to - * the namespace of the specified (Security Layer command) element. - * - * throws XpathException If the specified element has a namespace other than the ones - * known by this implementation as valid Security Layer namespaces (cf. - * @link Constants#SL10_NS_URI, @link Constants#SL11_NS_URI, @link Constants#SL12_NS_URI). + * Returns the namespace prefix used within XPathUtils for referring to the namespace + * of the specified (Security Layer command) element. + *

+ * This namespace prefix can be used in various XPath expression evaluation methods within + * XPathUtils without explicitely binding it to the particular namespace. + *

+ * @param contextElement The (Security Layer command) element. + * + * @return the namespace prefix used within XPathUtils for referring to the namespace + * of the specified (Security Layer command) element. + * + * throws XpathException If the specified element has a namespace other than the ones + * known by this implementation as valid Security Layer namespaces (cf. + * @link Constants#SL10_NS_URI, @link Constants#SL11_NS_URI, @link Constants#SL12_NS_URI). */ - public static String getSlPrefix (Element contextElement) throws XPathException - { - String sLNamespace = contextElement.getNamespaceURI(); - String sLPrefix = null; - - if (sLNamespace.equals(XMLNamespaceConstants.SL10_NS_URI)) - sLPrefix = XMLNamespaceConstants.SL10_PREFIX; - - else if (sLNamespace.equals(XMLNamespaceConstants.SL12_NS_URI)) - sLPrefix = XMLNamespaceConstants.SL12_PREFIX; - - else if (sLNamespace.equals(XMLNamespaceConstants.SL11_NS_URI)) - sLPrefix = XMLNamespaceConstants.SL11_PREFIX; - - else - throw new XPathException("XPath operation FAILED. Reason: "); - - return sLPrefix; + public static String getSlPrefix(final Element contextElement) throws XPathException { + final String sLNamespace = contextElement.getNamespaceURI(); + String slPrefix = null; + + if (sLNamespace.equals(XMLNamespaceConstants.SL10_NS_URI)) { + slPrefix = XMLNamespaceConstants.SL10_PREFIX; + } else if (sLNamespace.equals(XMLNamespaceConstants.SL12_NS_URI)) { + slPrefix = XMLNamespaceConstants.SL12_PREFIX; + } else if (sLNamespace.equals(XMLNamespaceConstants.SL11_NS_URI)) { + slPrefix = XMLNamespaceConstants.SL11_PREFIX; + } else { + throw new XPathException("XPath operation FAILED. Reason: "); + } + + return slPrefix; } - - + + /** - * Return the SecurityLayer namespace prefix of the context element. - * If the context element is not the element that lies within the - * SecurityLayer namespace. The Securitylayer namespace is derived from - * the xmlns:sl10, sl11 or sl - * attribute of the context element. - * + * Return the SecurityLayer namespace prefix of the context element. If the context element is not + * the element that lies within the SecurityLayer namespace. The Securitylayer namespace is + * derived from the xmlns:sl10, sl11 or sl attribute of the + * context element. + *

* The returned prefix is needed for evaluating XPATH expressions. - * - * @param contextElement The element to get a prefix for the Securitylayer namespace, - * that is used within the corresponding document. - * - * @return The string sl10, sl11 or sl, - * depending on the SecurityLayer namespace of the contextElement. - * - * throws XPathException If no (vlalid) SecurityLayer namespace prefix or namespace - * is defined. + *

+ * @param contextElement The element to get a prefix for the Securitylayer namespace, that is used + * within the corresponding document. + * + * @return The string sl10, sl11 or sl, depending on the + * SecurityLayer namespace of the contextElement. + * + * throws XPathException If no (vlalid) SecurityLayer namespace prefix or namespace is + * defined. */ - public static String getSlPrefixFromNoRoot (Element contextElement) throws XPathException { - - String slPrefix = checkSLnsDeclaration(contextElement, XMLNamespaceConstants.SL10_PREFIX, XMLNamespaceConstants.SL10_NS_URI); - if (slPrefix == null) - slPrefix = checkSLnsDeclaration(contextElement, XMLNamespaceConstants.SL11_PREFIX, XMLNamespaceConstants.SL11_NS_URI); - - if (slPrefix == null) - slPrefix = checkSLnsDeclaration(contextElement, XMLNamespaceConstants.SL12_PREFIX, XMLNamespaceConstants.SL12_NS_URI); - + public static String getSlPrefixFromNoRoot(final Element contextElement) throws XPathException { + + String slPrefix = checkSLnsDeclaration(contextElement, XMLNamespaceConstants.SL10_PREFIX, + XMLNamespaceConstants.SL10_NS_URI); + if (slPrefix == null) { + slPrefix = checkSLnsDeclaration(contextElement, XMLNamespaceConstants.SL11_PREFIX, + XMLNamespaceConstants.SL11_NS_URI); + } + + if (slPrefix == null) { + slPrefix = checkSLnsDeclaration(contextElement, XMLNamespaceConstants.SL12_PREFIX, + XMLNamespaceConstants.SL12_NS_URI); + } + return slPrefix; - + } - + /** - * Checks if the context element has an attribute xmlns:slPrefix and - * if the prefix of that attribute corresponds with a valid SecurityLayer namespace. - * - * @param contextElement The element to be checked. - * @param slPrefix The prefix which should be checked. Must be a valid SecurityLayer - * namespace prefix. - * @param slNameSpace The SecurityLayer namespace that corresponds to the specified prefix. - * - * @return The valid SecurityLayer prefix or null if this prefix is - * not used. - * @throws XPathException + * Checks if the context element has an attribute xmlns:slPrefix and if the prefix of + * that attribute corresponds with a valid SecurityLayer namespace. + * + * @param contextElement The element to be checked. + * @param slPrefix The prefix which should be checked. Must be a valid SecurityLayer namespace + * prefix. + * @param slNameSpace The SecurityLayer namespace that corresponds to the specified prefix. + * + * @return The valid SecurityLayer prefix or null if this prefix is not used. + * @throws XPathException In case of an error */ - private static String checkSLnsDeclaration(Element contextElement, String slPrefix, String slNameSpace) - throws XPathException - { - String nsAtt = "xmlns:" + slPrefix; - String nameSpace = contextElement.getAttribute(nsAtt); + private static String checkSLnsDeclaration(final Element contextElement, final String slPrefix, + final String slNameSpace) throws XPathException { + final String nsAtt = "xmlns:" + slPrefix; + final String nameSpace = contextElement.getAttribute(nsAtt); if (nameSpace == "") { return null; - + } else { // check if namespace is correct - if (nameSpace.equals(slNameSpace)) + if (nameSpace.equals(slNameSpace)) { return slPrefix; - else - throw new XPathException("Unknown Namespace declaration"); + } else { + throw new XPathException("Unknown Namespace declaration"); + } } } -- cgit v1.2.3