/*
* 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.jackrabbit.core.util;
import org.w3c.dom.Document;
import org.w3c.dom.Element;
import javax.xml.parsers.DocumentBuilder;
import javax.xml.parsers.DocumentBuilderFactory;
import javax.xml.parsers.ParserConfigurationException;
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 java.io.IOException;
import java.io.OutputStream;
/**
* Document builder class. This class provides an intuitive
* interface for incrementally building DOM documents.
*/
public final class DOMBuilder {
/** Static factory for creating DOM DocumentBuilder instances. */
private static final DocumentBuilderFactory BUILDER_FACTORY =
DocumentBuilderFactory.newInstance();
/** Static factory for creating document to output stream transformers. */
private static final TransformerFactory TRANSFORMER_FACTORY =
TransformerFactory.newInstance();
/** The DOM document being built by this builder. */
private final Document document;
/** The current element. */
private Element current;
/**
* Creates a builder for a new DOM document. A new DOM document is
* instantiated and initialized to contain a root element with the given
* name. The root element is set as the current element of this builder.
*
* @param name name of the root element
* @throws ParserConfigurationException if a document cannot be created
*/
public DOMBuilder(String name) throws ParserConfigurationException {
DocumentBuilder builder = BUILDER_FACTORY.newDocumentBuilder();
document = builder.newDocument();
current = document.createElement(name);
document.appendChild(current);
}
/**
* Writes the document built by this builder into the given output stream.
* This method is normally invoked only when the document is fully built.
*
* @param xml XML output stream
* @throws IOException if the document could not be written
*/
public void write(OutputStream xml) throws IOException {
try {
Transformer transformer = TRANSFORMER_FACTORY.newTransformer();
transformer.transform(
new DOMSource(document), new StreamResult(xml));
} catch (TransformerConfigurationException e) {
IOException ioe = new IOException(e.getMessage());
ioe.initCause(e);
throw ioe;
} catch (TransformerException e) {
IOException ioe = new IOException(e.getMessage());
ioe.initCause(e);
throw ioe;
}
}
/**
* Creates a new element with the given name as the child of the
* current element and makes the created element current. The
* {@link #endElement() endElement} method needs to be called
* to return back to the original element.
*
* @param name name of the new element
*/
public void startElement(String name) {
Element element = document.createElement(name);
current.appendChild(element);
current = element;
}
/**
* Makes the parent element current. This method should be invoked
* after a child element created with the
* {@link #startElement(String) startElement} method has been fully
* built.
*/
public void endElement() {
current = (Element) current.getParentNode();
}
/**
* Sets the named attribute of the current element.
*
* @param name attribute name
* @param value attribute value
*/
public void setAttribute(String name, String value) {
current.setAttribute(name, value);
}
/**
* Sets the named boolean attribute of the current element.
*
* @param name attribute name
* @param value boolean attribute value
*/
public void setAttribute(String name, boolean value) {
setAttribute(name, String.valueOf(value));
}
/**
* Adds the given string as text content to the current element.
*
* @param content text content
*/
public void addContent(String content) {
current.appendChild(document.createTextNode(content));
}
/**
* Adds a new child element with the given name and text content.
* The created element will contain no attributes and no child elements
* of its own.
*
* @param name child element name
* @param content child element content
*/
public void addContentElement(String name, String content) {
startElement(name);
addContent(content);
endElement();
}
}