blob: 9727d58dddbbfb558f7500dfe7c502f0d4d36b09 [file] [log] [blame]
/*
* Licensed to the Apache Software Foundation (ASF) under one or more
* contributor license agreements. See the NOTICE file distributed with
* this work for additional information regarding copyright ownership.
* The ASF licenses this file to You under the Apache License, Version 2.0
* (the "License"); you may not use this file except in compliance with
* the License. You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*
*/
package org.apache.lenya.xml;
import java.io.ByteArrayInputStream;
import java.io.File;
import java.io.IOException;
import java.io.InputStream;
import java.io.OutputStream;
import java.io.Writer;
import java.net.URI;
import java.net.URL;
import java.util.ArrayList;
import java.util.List;
import javax.xml.parsers.DocumentBuilder;
import javax.xml.parsers.DocumentBuilderFactory;
import javax.xml.parsers.ParserConfigurationException;
import javax.xml.transform.OutputKeys;
import javax.xml.transform.Transformer;
import javax.xml.transform.TransformerConfigurationException;
import javax.xml.transform.TransformerException;
import javax.xml.transform.TransformerFactory;
import javax.xml.transform.dom.DOMSource;
import javax.xml.transform.stream.StreamResult;
import org.apache.xml.resolver.tools.CatalogResolver;
import org.w3c.dom.DOMException;
import org.w3c.dom.Document;
import org.w3c.dom.DocumentType;
import org.w3c.dom.Element;
import org.w3c.dom.Node;
import org.w3c.dom.NodeList;
import org.w3c.dom.Text;
import org.xml.sax.SAXException;
/**
* Various utility methods to work with JAXP.
* @version $Id$
*/
public class DocumentHelper {
/**
* Creates a non-validating and namespace-aware DocumentBuilder.
* @return A new DocumentBuilder object.
* @throws ParserConfigurationException if an error occurs
*/
public static DocumentBuilder createBuilder() throws ParserConfigurationException {
DocumentBuilderFactory factory = DocumentBuilderFactory.newInstance();
factory.setNamespaceAware(true);
DocumentBuilder builder = factory.newDocumentBuilder();
CatalogResolver cr = new CatalogResolver();
builder.setEntityResolver(cr);
return builder;
}
/**
* Creates a document. A xmlns:prefix="namespaceUri" attribute is added to
* the document element.
* @param namespaceUri The namespace URL of the root element.
* @param qualifiedName The qualified name of the root element.
* @param documentType The type of document to be created or null. When
* doctype is not null, its Node.ownerDocument attribute is set
* to the document being created.
* @return A new Document object.
* @throws DOMException if an error occurs
* @throws ParserConfigurationException if an error occurs
* @see org.w3c.dom.DOMImplementation#createDocument(String, String,
* DocumentType)
*/
public static Document createDocument(String namespaceUri, String qualifiedName,
DocumentType documentType) throws DOMException, ParserConfigurationException {
DocumentBuilder builder = createBuilder();
Document document = builder.getDOMImplementation().createDocument(namespaceUri,
qualifiedName,
documentType);
// add xmlns:prefix attribute
String name = "xmlns";
int index = qualifiedName.indexOf(":");
if (index > -1) {
name += (":" + qualifiedName.substring(0, index));
}
document.getDocumentElement().setAttributeNS("http://www.w3.org/2000/xmlns/",
name,
namespaceUri);
return document;
}
/**
* Reads a document from a file.
* @return A document.
* @param file The file to load the document from.
* @throws ParserConfigurationException if an error occurs
* @throws SAXException if an error occurs
* @throws IOException if an error occurs
*/
public static Document readDocument(File file) throws ParserConfigurationException,
SAXException, IOException {
DocumentBuilder builder = createBuilder();
return builder.parse(file);
}
/**
* Reads a document from a URL.
* @return A document.
* @param url The URL to load the document from.
* @throws ParserConfigurationException if an error occurs
* @throws SAXException if an error occurs
* @throws IOException if an error occurs
*/
public static Document readDocument(URL url) throws ParserConfigurationException, SAXException,
IOException {
DocumentBuilder builder = createBuilder();
return builder.parse(url.toString());
}
/**
* Reads a document from a URI.
* @return A document.
* @param uri The URI to load the document from.
* @throws ParserConfigurationException if an error occurs
* @throws SAXException if an error occurs
* @throws IOException if an error occurs
*/
public static Document readDocument(URI uri) throws ParserConfigurationException, SAXException,
IOException {
DocumentBuilder builder = createBuilder();
return builder.parse(uri.toString());
}
/**
* Reads a document from a string.
* @return A document.
* @param string The string to load the document from.
* @param encoding The encoding which is used by the string.
* @throws ParserConfigurationException if an error occurs
* @throws SAXException if an error occurs
* @throws IOException if an error occurs
*/
public static Document readDocument(String string, String encoding) throws ParserConfigurationException,
SAXException, IOException {
DocumentBuilder builder = createBuilder();
byte bytes[] = string.getBytes(encoding);
ByteArrayInputStream stream = new ByteArrayInputStream(bytes);
return builder.parse(stream);
}
/**
* Reads a document from an input stream.
* @return A document.
* @param stream The input stream to load the document from.
* @throws ParserConfigurationException if an error occurs
* @throws SAXException if an error occurs
* @throws IOException if an error occurs
*/
public static Document readDocument(InputStream stream) throws ParserConfigurationException,
SAXException, IOException {
DocumentBuilder builder = createBuilder();
return builder.parse(stream);
}
/**
* Writes a document to a file. A new file is created if it does not exist.
* @param document The document to save.
* @param file The file to save the document to.
* @throws IOException if an error occurs
* @throws TransformerConfigurationException if an error occurs
* @throws TransformerException if an error occurs
*/
public static void writeDocument(Document document, File file)
throws TransformerConfigurationException, TransformerException, IOException {
// sanity checks
if (document == null)
throw new IllegalArgumentException("illegal usage, parameter document may not be null");
if (file == null)
throw new IllegalArgumentException("illegal usage, parameter file may not be null");
file.getParentFile().mkdirs();
file.createNewFile();
DOMSource source = new DOMSource(document);
StreamResult result = new StreamResult(file);
getTransformer(document.getDoctype()).transform(source, result);
}
/**
* Writes a document to a writer.
* @param document The document to write.
* @param writer The writer to write the document to.
* @throws TransformerConfigurationException if an error occurs
* @throws TransformerException if an error occurs
*/
public static void writeDocument(Document document, Writer writer)
throws TransformerConfigurationException, TransformerException {
// sanity checks
if (document == null)
throw new IllegalArgumentException("illegal usage of DocumentHelper::writeDocument(), parameter document may not be null");
DOMSource source = new DOMSource(document);
StreamResult result = new StreamResult(writer);
getTransformer(document.getDoctype()).transform(source, result);
}
/**
* Writes a document to an output stream.
* @param document The document to write.
* @param outputStream The stream to write the document to.
* @throws TransformerConfigurationException if an error occurs
* @throws TransformerException if an error occurs
*/
public static void writeDocument(Document document, OutputStream outputStream)
throws TransformerConfigurationException, TransformerException {
// sanity checks
if (document == null)
throw new IllegalArgumentException("illegal usage of DocumentHelper::writeDocument(), parameter document may not be null");
DOMSource source = new DOMSource(document);
StreamResult result = new StreamResult(outputStream);
try {
getTransformer(document.getDoctype()).transform(source, result);
}
finally {
try {
if (outputStream != null) {
outputStream.close();
}
}
catch (Exception ignore) {
}
}
}
/**
* Get the transformer.
* @param documentType the document type
* @return a transformer
* @throws TransformerConfigurationException if an error occurs
*/
protected static Transformer getTransformer(DocumentType documentType)
throws TransformerConfigurationException {
TransformerFactory factory = TransformerFactory.newInstance();
Transformer transformer = factory.newTransformer();
transformer.setOutputProperty(OutputKeys.INDENT, "yes");
transformer.setOutputProperty(OutputKeys.METHOD, "xml");
if (documentType != null) {
if (documentType.getPublicId() != null)
transformer.setOutputProperty(OutputKeys.DOCTYPE_PUBLIC, documentType.getPublicId());
if (documentType.getSystemId() != null)
transformer.setOutputProperty(OutputKeys.DOCTYPE_SYSTEM, documentType.getSystemId());
}
return transformer;
}
/**
* Creates a document type.
* @param qualifiedName The qualified name of the document type.
* @param publicId The public identifier.
* @param systemId The system identifier.
* @return the document type
* @throws ParserConfigurationException if an error occurs
* @see org.w3c.dom.DOMImplementation#createDocumentType(java.lang.String,
* java.lang.String, java.lang.String)
*/
public DocumentType createDocumentType(String qualifiedName, String publicId, String systemId)
throws ParserConfigurationException {
DocumentBuilder builder = createBuilder();
return builder.getDOMImplementation().createDocumentType(qualifiedName, publicId, systemId);
}
/**
* Returns the first child element of an element that belong to a certain
* namespace or <code>null</code> if none exists.
* @param element The parent element.
* @param namespaceUri The namespace that the childen must belong to.
* @return The first child element or <code>null</code> if none exists.
*/
public static Element getFirstChild(Element element, String namespaceUri) {
return getFirstChild(element, namespaceUri, "*");
}
/**
* Returns the first child element of an element that belongs to a certain
* namespace and has a certain local name or <code>null</code> if none
* exists.
* @param element The parent element.
* @param namespaceUri The namespace that the childen must belong to.
* @param localName The local name of the children.
* @return The child element or <code>null</code> if none exists.
*/
public static Element getFirstChild(Element element, String namespaceUri, String localName) {
Element[] children = getChildren(element, namespaceUri, localName);
if (children.length > 0) {
return children[0];
}
return null;
}
/**
* Returns all child elements of an element, regardless of the namespace.
* @param element The parent element.
* @return The child elements.
*/
public static Element[] getChildren(Element element) {
List childElements = new ArrayList();
NodeList children = element.getElementsByTagName("*");
for (int i = 0; i < children.getLength(); i++) {
if (children.item(i).getParentNode() == element) {
childElements.add(children.item(i));
}
}
return (Element[]) childElements.toArray(new Element[childElements.size()]);
}
/**
* Returns all child elements of an element that belong to a certain
* namespace.
* @param element The parent element.
* @param namespaceUri The namespace that the childen must belong to.
* @return The child elements.
*/
public static Element[] getChildren(Element element, String namespaceUri) {
return getChildren(element, namespaceUri, "*");
}
/**
* Returns all child elements of an element that belong to a certain
* namespace and have a certain local name.
* @param element The parent element.
* @param namespaceUri The namespace that the childen must belong to.
* @param localName The local name of the children.
* @return The child elements.
*/
public static Element[] getChildren(Element element, String namespaceUri, String localName) {
List childElements = new ArrayList();
NodeList children = element.getElementsByTagNameNS(namespaceUri, localName);
for (int i = 0; i < children.getLength(); i++) {
if (children.item(i).getParentNode() == element) {
childElements.add(children.item(i));
}
}
return (Element[]) childElements.toArray(new Element[childElements.size()]);
}
/**
* Returns the text inside an element. Only the child text nodes of this
* element are collected.
* @param element The element.
* @return The text inside the element.
*/
public static String getSimpleElementText(Element element) {
StringBuffer buffer = new StringBuffer();
NodeList children = element.getChildNodes();
for (int i = 0; i < children.getLength(); i++) {
Node child = children.item(i);
if (child instanceof Text) {
buffer.append(child.getNodeValue());
}
}
return buffer.toString();
}
/**
* Replaces all child nodes of an element by a single text node.
* @param element The element.
* @param text The text to insert.
*/
public static void setSimpleElementText(Element element, String text) {
NodeList children = element.getChildNodes();
for (int i = 0; i < children.getLength(); i++) {
Node child = children.item(i);
element.removeChild(child);
}
Node textNode = element.getOwnerDocument().createTextNode(text);
element.appendChild(textNode);
}
/**
* Returns all following sibling elements of an element that belong to a
* certain namespace.
* @param element The parent element.
* @param namespaceUri The namespace that the childen must belong to.
* @return The following sibling elements.
*/
public static Element[] getNextSiblings(Element element, String namespaceUri) {
return getNextSiblings(element, namespaceUri, "*");
}
/**
* Returns all following sibling elements of an element that belong to a
* certain namespace. and have a certain local name.
* @param element The parent element.
* @param namespaceUri The namespace that the childen must belong to.
* @param localName The local name of the children.
* @return The following sibling elements.
*/
public static Element[] getNextSiblings(Element element, String namespaceUri, String localName) {
List childElements = new ArrayList();
Element parent = (Element) element.getParentNode();
Element[] children = getChildren(parent, namespaceUri, localName);
int l = children.length;
for (int i = 0; i < children.length; i++) {
if (children[i] == element) {
l = i;
}
if (i > l) {
childElements.add(children[i]);
}
}
return (Element[]) childElements.toArray(new Element[childElements.size()]);
}
/**
* Returns all preceding sibling elements of an element that belong to a
* certain namespace.
* @param element The parent element.
* @param namespaceUri The namespace that the childen must belong to.
* @return The preceding sibling elements.
*/
public static Element[] getPrecedingSiblings(Element element, String namespaceUri) {
return getPrecedingSiblings(element, namespaceUri, "*");
}
/**
* Returns all preceding sibling elements of an element that belong to a
* certain namespace. and have a certain local name.
* @param element The parent element.
* @param namespaceUri The namespace that the childen must belong to.
* @param localName The local name of the children.
* @return The preceding sibling elements.
*/
public static Element[] getPrecedingSiblings(Element element, String namespaceUri,
String localName) {
List childElements = new ArrayList();
Element parent = (Element) element.getParentNode();
Element[] children = getChildren(parent, namespaceUri, localName);
int i = 0;
while (children[i] != element && i < children.length) {
childElements.add(children[i]);
i++;
}
return (Element[]) childElements.toArray(new Element[childElements.size()]);
}
}