net.sf.javagimmicks.xml.DOMUtils Maven / Gradle / Ivy
Go to download
Show more of this group Show more artifacts with this name
Show all versions of gimmicks Show documentation
Show all versions of gimmicks Show documentation
Utility classes, APIs and tools for Java
package net.sf.javagimmicks.xml;
import java.io.IOException;
import java.io.InputStream;
import java.io.OutputStream;
import java.io.OutputStreamWriter;
import java.io.Reader;
import java.io.StringReader;
import java.io.Writer;
import java.util.AbstractList;
import java.util.ArrayList;
import java.util.Collections;
import java.util.HashMap;
import java.util.HashSet;
import java.util.List;
import java.util.Map;
import java.util.Set;
import javax.xml.parsers.DocumentBuilder;
import javax.xml.parsers.DocumentBuilderFactory;
import javax.xml.parsers.ParserConfigurationException;
import javax.xml.xpath.XPathConstants;
import javax.xml.xpath.XPathExpressionException;
import javax.xml.xpath.XPathFactory;
import org.w3c.dom.Attr;
import org.w3c.dom.DOMImplementation;
import org.w3c.dom.Document;
import org.w3c.dom.Element;
import org.w3c.dom.NamedNodeMap;
import org.w3c.dom.Node;
import org.w3c.dom.NodeList;
import org.w3c.dom.ls.DOMImplementationLS;
import org.w3c.dom.ls.LSOutput;
import org.w3c.dom.ls.LSSerializer;
import org.xml.sax.InputSource;
import org.xml.sax.SAXException;
/**
* Provides several helper methods for advances dealing with W3C XML
* {@link Document}s.
*/
public class DOMUtils
{
private static final String PARAM_PRETTY_PRINT = "format-pretty-print";
private static DocumentBuilderFactory _dbf = DocumentBuilderFactory.newInstance();
private static XPathFactory _xpf = XPathFactory.newInstance();
static
{
_dbf.setNamespaceAware(true);
}
private DOMUtils()
{}
/**
* Retrieves all child {@link Element}s from a given parent {@link Element}
* as {@link List}.
*
* @param element
* the parent {@link Element}
* @return the {@link List} of child {@link Element}s
*/
public static List getChildElements(final Element element)
{
final List result = new ArrayList();
for (Node child = element.getFirstChild(); child != null; child = child.getNextSibling())
{
if (!(child instanceof Element))
{
continue;
}
result.add((Element) child);
}
return result;
}
/**
* Retrieves all child {@link Element}s of a given namespace URI and local
* name from a given parent {@link Element} as {@link List}.
*
* @param element
* the parent {@link Element}
* @param namespaceURI
* the namespace URI of the child {@link Element}s to retrieve
* @param localName
* the local name of the child {@link Element}s to retrieve
* @return the respective {@link List} of child {@link Element}s
*/
public static List getChildElements(final Element element, final String namespaceURI,
final String localName)
{
final List result = new ArrayList();
for (Node child = element.getFirstChild(); child != null; child = child.getNextSibling())
{
if (!(child instanceof Element))
{
continue;
}
if (namespaceURI != null && !namespaceURI.equals(child.getNamespaceURI()))
{
continue;
}
if (!localName.equals(child.getLocalName()))
{
continue;
}
result.add((Element) child);
}
return result;
}
/**
* Retrieves all child {@link Element}s of a given local name from a given
* parent {@link Element} as {@link List}.
*
* @param element
* the parent {@link Element}
* @param localName
* the local name of the child {@link Element}s to retrieve
* @return the respective {@link List} of child {@link Element}s
*/
public static List getChildElements(final Element element, final String localName)
{
final List result = new ArrayList();
for (Node child = element.getFirstChild(); child != null; child = child.getNextSibling())
{
if (!(child instanceof Element))
{
continue;
}
if (!localName.equals(child.getNodeName()))
{
continue;
}
result.add((Element) child);
}
return result;
}
/**
* Retrieves all {@link Attr Attribute}s from a given parent {@link Element}
* as {@link List}.
*
* @param element
* the parent {@link Element}
* @return the {@link List} of {@link Attr Attribute}s
*/
public static List getAttributes(final Element element)
{
final NamedNodeMap attributes = element.getAttributes();
return new AbstractList()
{
@Override
public Attr get(final int index)
{
return (Attr) attributes.item(index);
}
@Override
public int size()
{
return attributes.getLength();
}
};
}
/**
* Creates and returns a new {@link DocumentBuilder}.
*
* @return a new {@link DocumentBuilder}
* @throws ParserConfigurationException
* if the creation fails
*/
public static DocumentBuilder newDocumentBuilder() throws ParserConfigurationException
{
return _dbf.newDocumentBuilder();
}
/**
* Creates and returns a new {@link Document}.
*
* @return a new {@link Document}
* @throws ParserConfigurationException
* if the creation fails
*/
public static Document newDocument() throws ParserConfigurationException
{
return newDocumentBuilder().newDocument();
}
/**
* Creates and returns a new {@link Document} with a root {@link Element}
* according to the given parameters.
*
* @param nsUri
* the namespace URI for the root {@link Element}
* @param prefix
* the prefix for the root {@link Element}
* @param localName
* the local name for the root {@link Element}
* @return a new according {@link Document}
* @throws ParserConfigurationException
* if the creation fails
*/
public static Document newDocument(final String nsUri, final String prefix, final String localName)
throws ParserConfigurationException
{
final String qualifiedName = (prefix == null ? "" : (prefix + ":")) + localName;
return getDOMImplementation().createDocument(nsUri, qualifiedName, null);
}
/**
* Creates and returns a new {@link Document} with a root {@link Element}
* according to the given parameters.
*
* @param nsUri
* the namespace URI for the root {@link Element}
* @param localName
* the local name for the root {@link Element}
* @return a new according {@link Document}
* @throws ParserConfigurationException
* if the creation fails
*/
public static Document newDocument(final String nsUri, final String localName)
throws ParserConfigurationException
{
return newDocument(nsUri, null, localName);
}
/**
* Creates and returns a new {@link Document} with a root {@link Element}
* according to the given parameters.
*
* @param localName
* the local name URI for the root {@link Element}
* @return a new according {@link Document}
* @throws ParserConfigurationException
* if the creation fails
*/
public static Document newDocument(final String localName) throws ParserConfigurationException
{
return newDocument(null, localName);
}
/**
* Creates and returns a new {@link DOMImplementation}.
*
* @return a new {@link DOMImplementation}
* @throws ParserConfigurationException
* if the creation fails
*/
public static DOMImplementation getDOMImplementation() throws ParserConfigurationException
{
return newDocumentBuilder().getDOMImplementation();
}
/**
* Parses a new XML {@link Document} from a given {@link InputSource}
*
* @param inputSource
* the {@link InputSource} to parse from
* @return the parsed {@link Document}
* @throws SAXException
* if the XML source is not valid
* @throws IOException
* if the source could not be read
* @throws ParserConfigurationException
* if the parser could not be created
*/
public static Document parse(final InputSource inputSource) throws SAXException, IOException,
ParserConfigurationException
{
return newDocumentBuilder().parse(inputSource);
}
/**
* Parses a new XML {@link Document} from a given {@link InputStream}
*
* @param inputStream
* the {@link InputStream} to parse from
* @return the parsed {@link Document}
* @throws SAXException
* if the XML source is not valid
* @throws IOException
* if the source could not be read
* @throws ParserConfigurationException
* if the parser could not be created
*/
public static Document parse(final InputStream inputStream) throws SAXException, IOException,
ParserConfigurationException
{
return parse(new InputSource(inputStream));
}
/**
* Parses a new XML {@link Document} from a given {@link Reader}
*
* @param reader
* the {@link Reader} to parse from
* @return the parsed {@link Document}
* @throws SAXException
* if the XML source is not valid
* @throws IOException
* if the source could not be read
* @throws ParserConfigurationException
* if the parser could not be created
*/
public static Document parse(final Reader reader) throws SAXException, IOException, ParserConfigurationException
{
return parse(new InputSource(reader));
}
/**
* Parses a new XML {@link Document} from a given XML {@link String}.
*
* @param xmlContent
* the XML {@link String} to parse from
* @return the parsed {@link Document}
* @throws SAXException
* if the XML source is not valid
* @throws IOException
* if the source could not be read
* @throws ParserConfigurationException
* if the parser could not be created
*/
public static Document parse(final String xmlContent) throws SAXException, IOException,
ParserConfigurationException
{
return parse(new StringReader(xmlContent));
}
/**
* Serializes a given XML {@link Node} into a {@link String} with optionally
* pretty-printing.
*
* @param node
* the {@link Node} to serialize
* @param prettyPrint
* if pretty-printing should be applied
* @return the serialized XML {@link String}
* @throws ParserConfigurationException
* if the serializer could not be created
*/
public static String serialize(final Node node, final boolean prettyPrint) throws ParserConfigurationException
{
final DOMImplementationLS domImpl = (DOMImplementationLS) getDOMImplementation();
final LSSerializer serializer = domImpl.createLSSerializer();
serializer.getDomConfig().setParameter(PARAM_PRETTY_PRINT, prettyPrint);
return serializer.writeToString(node);
}
/**
* Serializes a given XML {@link Node} into a {@link Writer} with optionally
* pretty-printing.
*
* @param node
* the {@link Node} to serialize
* @param writer
* the {@link Writer} where the {@link Node} should be serialized
* @param prettyPrint
* if pretty-printing should be applied
* @throws ParserConfigurationException
* if the serializer could not be created
*/
public static void serialize(final Node node, final Writer writer, final boolean prettyPrint)
throws ParserConfigurationException
{
final DOMImplementationLS domImpl = (DOMImplementationLS) newDocumentBuilder().getDOMImplementation();
final LSSerializer serializer = domImpl.createLSSerializer();
serializer.getDomConfig().setParameter(PARAM_PRETTY_PRINT, prettyPrint);
final LSOutput output = domImpl.createLSOutput();
output.setCharacterStream(writer);
serializer.write(node, output);
}
/**
* Serializes a given XML {@link Node} into a {@link OutputStream} with
* optionally pretty-printing.
*
* @param node
* the {@link Node} to serialize
* @param outputStream
* the {@link OutputStream} where the {@link Node} should be
* serialized
* @param prettyPrint
* if pretty-printing should be applied
* @throws ParserConfigurationException
* if the serializer could not be created
*/
public static void serialize(final Node node, final OutputStream outputStream, final boolean prettyPrint)
throws ParserConfigurationException
{
serialize(node, new OutputStreamWriter(outputStream), prettyPrint);
}
/**
* Adds a new child {@link Element} of the given namespaceUri, prefix and
* local name to a given parent {@link Element}.
*
* @param parent
* the parent {@link Element} where to add a new child
* @param namespaceUri
* the namespace URI for the new {@link Element}
* @param prefix
* the prefix for the new {@link Element}
* @param localName
* the local name for the new {@link Element}
* @return the new child {@link Element}
*/
public static Element addElement(final Element parent, final String namespaceUri, final String prefix,
final String localName)
{
final Element child = parent.getOwnerDocument().createElementNS(namespaceUri,
NameUtils.buildQualifiedName(prefix, localName));
parent.appendChild(child);
return child;
}
/**
* Adds a new child {@link Element} of the given namespaceUri and local name
* to a given parent {@link Element}.
*
* @param parent
* the parent {@link Element} where to add a new child
* @param namespaceUri
* the namespace URI for the new {@link Element}
* @param localName
* the local name for the new {@link Element}
* @return the new child {@link Element}
*/
public static Element addElement(final Element parent, final String namespaceUri, final String localName)
{
return addElement(parent, namespaceUri, null, localName);
}
/**
* Adds a new child {@link Element} of the given local name to a given parent
* {@link Element}.
*
* @param parent
* the parent {@link Element} where to add a new child
* @param localName
* the local name (tag name) for the new {@link Element}
* @return the new child {@link Element}
*/
public static Element addElement(final Element parent, final String localName)
{
final Element child = parent.getOwnerDocument().createElement(localName);
parent.appendChild(child);
return child;
}
public static Element addAttribute(final Element element, final String attributeName, final String value)
{
element.setAttribute(attributeName, value);
return element;
}
public static List wrapNodeList(final NodeList nodeList)
{
return new AbstractList()
{
@Override
public Node get(final int index)
{
return nodeList.item(index);
}
@Override
public int size()
{
return nodeList.getLength();
}
};
}
public static Node selectSingleNode(final Node node, final String xPath) throws XPathExpressionException
{
return (Node) _xpf.newXPath().evaluate(xPath, node, XPathConstants.NODE);
}
public static List selectNodes(final Node node, final String xPath) throws XPathExpressionException
{
return wrapNodeList((NodeList) _xpf.newXPath().evaluate(xPath, node, XPathConstants.NODE));
}
public static Element replaceNamespaces(Element element, final Map namespaceMap,
final boolean exchangeElementNames, final boolean exchangeAttributeNames)
{
// Handle the element name
if (exchangeElementNames)
{
// Get the Namespace from it and lookup the replacement in the map
final Namespace elementNamespace = Namespace.of(element);
final Namespace newNamespace = namespaceMap.get(elementNamespace);
// If there is a replacement, set the new QName
if (newNamespace != null)
{
element = newNamespace.applyTo(element);
}
}
// Iterate over all Namespaces declared in this element
// TODO: Check how/if this can be done with W3C
// List oDelcaredNamespaces = new
// ArrayList(oElement.declaredNamespaces());
// for(Namespace oDeclaredNamespace : oDelcaredNamespaces)
// {
// // Lookup the replacement in the map
// Namespace oNewDeclaredNamespace =
// oNamespaceMap.get(oDeclaredNamespace);
//
// // If there is a replacement, make the exchange
// if(oNewDeclaredNamespace != null)
// {
// oElement.remove(oDeclaredNamespace);
// oElement.add(oNewDeclaredNamespace);
// }
// }
// Handle the attribute names
if (exchangeAttributeNames)
{
for (final Attr attribute : getAttributes(element))
{
// Get the Namespace from the attribute and lookup the replacement
// in the map
final Namespace attributeNamespace = Namespace.of(attribute);
final Namespace newAttributeNamespace = namespaceMap.get(attributeNamespace);
// If there is a replacement, replace the whole attribute
if (newAttributeNamespace != null)
{
newAttributeNamespace.applyTo(attribute);
}
}
}
// Make the recursive call
for (final Element childElement : getChildElements(element))
{
replaceNamespaces(childElement, namespaceMap, exchangeElementNames, exchangeAttributeNames);
}
element.getOwnerDocument().normalizeDocument();
return element;
}
public static Element replaceNamespaces(final Element element, final Namespace fromNs, final Namespace toNs)
{
// Replace element names but not attribute names
return replaceNamespaces(element, fromNs, toNs, true, false);
}
public static Element replaceNamespaces(final Element element, final Namespace fromNs, final Namespace toNs,
final boolean exchangeElementNames, final boolean exchangeAttributeNames)
{
return replaceNamespaces(element, Collections.singletonMap(fromNs, toNs), exchangeElementNames,
exchangeAttributeNames);
}
public static Element replaceNamespaces(final Element element, final String fromURI, final Namespace toNs,
final boolean exchangeElementNames, final boolean exchangeAttributeNames)
{
final Map namespaceMap = new HashMap();
for (final Namespace fromNs : findNamespaces(element, fromURI))
{
namespaceMap.put(fromNs, toNs);
}
return replaceNamespaces(element, namespaceMap, exchangeElementNames,
exchangeAttributeNames);
}
public static Element replaceNamespaces(final Element element, final String fromURI, final Namespace toNs)
{
return replaceNamespaces(element, fromURI, toNs, true, false);
}
public static Element replaceNamespaces(final Element element, final Map namespaceMap)
{
// Replace element names but not attribute names
return replaceNamespaces(element, namespaceMap, true, false);
}
public static Set findNamespaces(final Element element, final String fromURI)
{
final Set oResult = new HashSet();
findNamespaces(element, fromURI, oResult);
return oResult;
}
private static void findNamespaces(final Element element, String uri, final Set namespaces)
{
if (uri == null)
{
uri = "";
}
final String currentUri = element.getNamespaceURI();
if ((currentUri == null && uri.length() == 0) || uri.equals(currentUri))
{
namespaces.add(Namespace.of(element));
}
// TODO: lookupPrefix delivers at maximum ONE prefix even though more
// might exist for the given URI! Is this a problem?
final String prefix = element.lookupPrefix(uri);
if (prefix != null)
{
namespaces.add(Namespace.get(prefix, uri));
}
for (final Element childElement : getChildElements(element))
{
findNamespaces(childElement, uri, namespaces);
}
}
static String getLocalName(final Node node)
{
final String result = node.getLocalName();
return result != null ? result : node.getNodeName();
}
}
© 2015 - 2025 Weber Informatics LLC | Privacy Policy