org.jvoicexml.xml.XmlDocument Maven / Gradle / Ivy
Go to download
Show more of this group Show more artifacts with this name
Show all versions of org.jvoicexml.xml Show documentation
Show all versions of org.jvoicexml.xml Show documentation
The Open Source Voice Browser
The newest version!
/*
* JVoiceXML - A free VoiceXML implementation.
*
* Copyright (C) 2005-2017 JVoiceXML group - http://jvoicexml.sourceforge.net
*
* This library is free software; you can redistribute it and/or
* modify it under the terms of the GNU Library General Public
* License as published by the Free Software Foundation; either
* version 2 of the License, or (at your option) any later version.
*
* This library is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* Library General Public License for more details.
*
* You should have received a copy of the GNU Library General Public
* License along with this library; if not, write to the Free Software
* Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
*
*/
package org.jvoicexml.xml;
import java.io.ByteArrayInputStream;
import java.io.ByteArrayOutputStream;
import java.io.IOException;
import java.io.ObjectInputStream;
import java.io.ObjectOutputStream;
import java.io.Serializable;
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.w3c.dom.Attr;
import org.w3c.dom.CDATASection;
import org.w3c.dom.Comment;
import org.w3c.dom.DOMConfiguration;
import org.w3c.dom.DOMImplementation;
import org.w3c.dom.Document;
import org.w3c.dom.DocumentFragment;
import org.w3c.dom.DocumentType;
import org.w3c.dom.Element;
import org.w3c.dom.EntityReference;
import org.w3c.dom.NamedNodeMap;
import org.w3c.dom.Node;
import org.w3c.dom.NodeList;
import org.w3c.dom.ProcessingInstruction;
import org.w3c.dom.Text;
import org.w3c.dom.UserDataHandler;
import org.xml.sax.EntityResolver;
import org.xml.sax.InputSource;
import org.xml.sax.SAXException;
/**
* An XML Document abstract base class.
*
*
* VoiceXML is designed for creating audio dialogs that feature synthesized
* speech, digitized audio, recognition of spoken and DTMF key input, recording
* of spoken input, telephony and mixed initiative conversations. Its major goal
* is to bring the advantages of web-based development and content delivery to
* interactive voice response applications.
*
*
*
* Objects of this class can create such VoiceXML documents or parse them.
*
*
*
* The encoding can be controlled via the
* jvoicexml.xml.encoding
environment property. The default
* value is UTF-8
.
*
*
* Entities are not resolved by default. The bahavior can be controlled via
* the system property org.jvoicexml.resolveEntities
.
*
* @author Steve Doyle
* @author Dirk Schnelle-Walka
*/
public abstract class XmlDocument
implements Document, Serializable {
/** The serial version UID. */
private static final long serialVersionUID = 2293026699195796236L;
/** The encapsulated document, implemented as a delegate. */
private transient Document document;
/**
* The document builder to use. Unfortunately, SAX parsing is not thread
* safe, so we store the builder in a thread local variable.
*/
private static final ThreadLocal LOCAL_BUILDER
= new ThreadLocal() {
@Override
protected DocumentBuilder initialValue() {
final DocumentBuilderFactory factory =
DocumentBuilderFactory.newInstance();
factory.setNamespaceAware(true);
// Configure the factory to ignore comments
factory.setIgnoringComments(true);
DocumentBuilder builder = null;
try {
builder = factory.newDocumentBuilder();
final EntityResolver resolver = new IgnoringEntityResolver();
boolean resolveEntities =
Boolean.getBoolean("org.jvoicexml.xml.resolveEntities");
if (!resolveEntities) {
builder.setEntityResolver(resolver);
}
} catch (ParserConfigurationException e) {
e.printStackTrace();
}
return builder;
};
};
/**
* Creates an empty XML document.
*
* @throws ParserConfigurationException
* Error creating the document builder.
*/
public XmlDocument()
throws ParserConfigurationException {
// Check if there is a document type specified.
final DocumentType prototype = getDoctype();
final DocumentBuilder builder = LOCAL_BUILDER.get();
if (prototype == null) {
// If there is none, simply create a new document as usual.
document = builder.newDocument();
if (document != null) {
final Node root = createRootNode();
appendChild(root);
}
} else {
// otherwise create a document with the given doctype as a
// prototype
final DOMImplementation impl = builder.getDOMImplementation();
final DocumentType type =
impl.createDocumentType(prototype.getName(),
prototype.getPublicId(), prototype.getSystemId());
document = impl.createDocument(getDefaultNamespaceURI(),
prototype.getName(), type);
}
}
/**
* Constructs a new XML document from the given input source.
*
* @param source
* Input source for a single XML document.
* @throws ParserConfigurationException
* Error creating the document builder.
* @throws SAXException
* Error parsing the input source.
* @throws IOException
* Error reading the input source.
*/
public XmlDocument(final InputSource source)
throws ParserConfigurationException, SAXException, IOException {
final DocumentBuilder builder = LOCAL_BUILDER.get();
document = builder.parse(source);
}
/**
* Construct a new XML document with the given document.
*
* @param doc
* Encapsulated document.
*/
public XmlDocument(final Document doc) {
Document current = doc;
while (current instanceof XmlDocument) {
final XmlDocument xmldocument = (XmlDocument) current;
current = xmldocument.getDocument();
if (current == null) {
current = xmldocument;
break;
}
}
document = current;
}
/**
* Retrieves the encapsulated document.
* @return The encapsulated document.
*/
public final Document getDocument() {
Document current = document;
while (current instanceof XmlDocument) {
final XmlDocument xmldocument = (XmlDocument) current;
current = xmldocument.getDocument();
if (current == null) {
return xmldocument;
}
}
return document;
}
/**
* Retrieves the node factory for child node lists.
* @return Node factory for child node lists.
*
* @since 0.5
*/
protected abstract XmlNodeFactory> getXmlNodefactory();
/**
* Create the root node of the document.
*
* @return Root node
*/
protected abstract Node createRootNode();
/**
* Adds the node newChild
to the end of the list of children
* of this node.
*
* @param newChild
* The node to add.If it is a DocumentFragment
object,
* the entire contents of the document fragment are moved into the
* child list of this node
* @return The node added.
*/
public final Node appendChild(final Node newChild) {
final Node insertChild;
if (newChild instanceof XmlNode) {
final XmlNode xmlNode = (XmlNode) newChild;
insertChild = xmlNode.getNode();
} else {
insertChild = newChild;
}
return document.appendChild(insertChild);
}
/**
* Returns a duplicate of this node, i.e., serves as a generic copy
* constructor for nodes.
*
* @param deep
* If true
, recursively clone the subtree under the
* specified node; if false
, clone only the node
* itself (and its attributes, if it is an Element
).
* @return The duplicate node.
*/
public final Node cloneNode(final boolean deep) {
return document.cloneNode(deep);
}
/**
* Creates an Attr
of the given name.
*
* @param name
* The name of the attribute.
* @return A new Attr
object with the nodeName
* attribute set to name
, and localName
,
* prefix
, and namespaceURI
set to
* null
. The value of the attribute is the empty
* string.
*/
public final Attr createAttribute(final String name) {
return document.createAttribute(name);
}
/**
* Creates an attribute of the given qualified name and namespace URI.
*
* @param namespaceURI
* The namespace URI of the attribute to create.
* @param qualifiedName
* The qualified name of the attribute to instantiate.
* @return A new Attr
object with the following attributes:
*
*
* Attribute
* Value
*
*
* Node.nodeName
* qualifiedName
*
*
* Node.namespaceURI
* namespaceURI
*
*
* Node.prefix
* prefix, extracted from
* qualifiedName
, or null
if there is
* no prefix
*
*
* Node.localName
* local name, extracted from
* qualifiedName
*
*
* Attr.name
* qualifiedName
*
*
* Node.nodeValue
* the empty string
*
*
*/
public final Attr createAttributeNS(final String namespaceURI,
final String qualifiedName) {
return document.createAttributeNS(namespaceURI, qualifiedName);
}
/**
* Creates a CDATASection
node whose value is the specified
* string.
*
* @param data
* The data for the CDATASection
contents.
* @return The new CDATASection
object.
*/
public final CDATASection createCDATASection(final String data) {
return document.createCDATASection(data);
}
/**
* Creates a Comment
node given the specified string.
*
* @param data
* The data for the node.
* @return The new Comment
object.
*/
public final Comment createComment(final String data) {
return document.createComment(data);
}
/**
* Creates an empty DocumentFragment
object.
*
* @return A new DocumentFragment
.
*/
public final DocumentFragment createDocumentFragment() {
return document.createDocumentFragment();
}
/**
* Creates an element of the type specified.
*
* @param tagName
* The name of the element type to instantiate. For XML, this is
* case-sensitive. For HTML, the tagName
parameter may
* be provided in any case, but it must be mapped to the canonical
* uppercase form by the DOM implementation.
* @return A new Element
object with the
* nodeName
attribute set to tagName
,
* and localName
, prefix
, and
* namespaceURI
set to null
.
*/
public final Element createElement(final String tagName) {
return document.createElement(tagName);
}
/**
* Creates an element of the given qualified name and namespace URI.
*
* @param namespaceURI
* The namespace URI of the element to create.
* @param qualifiedName
* The qualified name of the element type to instantiate.
* @return A new Element
object with the following
* attributes:
*
* Attribute
* Value
*
*
* Node.nodeName
* qualifiedName
*
*
* Node.namespaceURI
* namespaceURI
*
*
* Node.prefix
* prefix, extracted from
* qualifiedName
, or null
if there is
* no prefix
*
*
* Node.localName
* local name, extracted from
* qualifiedName
*
*
* Element.tagName
* qualifiedName
*
*
*/
public final Element createElementNS(final String namespaceURI,
final String qualifiedName) {
return document.createElementNS(namespaceURI, qualifiedName);
}
/**
* Creates an EntityReference
object.
*
* @param name
* The name of the entity to reference.
* @return The new EntityReference
object.
*/
public final EntityReference createEntityReference(final String name) {
return document.createEntityReference(name);
}
/**
* Creates a ProcessingInstruction
node given the specified
* name and data strings.
*
* @param target
* The target part of the processing instruction.
* @param data
* The data for the node.
* @return The new ProcessingInstruction
object.
*/
public final ProcessingInstruction createProcessingInstruction(
final String target, final String data) {
return document.createProcessingInstruction(target, data);
}
/**
* Creates a Text
node given the specified string.
*
* @param data
* The data for the node.
* @return The new Text
object.
*/
public final Text createTextNode(final String data) {
return document.createTextNode(data);
}
/**
* A NamedNodeMap
containing the attributes of this node (if
* it is an Element
) or null
otherwise.
*
* @return NamedNodeMap
*/
public final NamedNodeMap getAttributes() {
return document.getAttributes();
}
/**
* A NodeList
that contains all children of this node.
*
* @return NodeList
*/
public final NodeList getChildNodes() {
final NodeList children = document.getChildNodes();
return getXmlNodeList(children);
}
/**
* Retrieves the Document Type Declaration associated with this document.
* null
if there is none
*
* @return the associated document type
* @see DocumentType
*/
public DocumentType getDoctype() {
if (document == null) {
return null;
}
return document.getDoctype();
}
/**
* This is a convenience attribute that allows direct access to the child
* node that is the root element of the document.
*
* @return Element
*/
public final Element getDocumentElement() {
return document.getDocumentElement();
}
/**
* Returns the Element
whose ID
is given by
* elementId
.
*
* @param elementId
* The unique id
value for an element.
* @return The matching element.
*/
public final Element getElementById(final String elementId) {
return document.getElementById(elementId);
}
/**
* Returns a NodeList
of all the Elements
with
* a given tag name in the order in which they are encountered in a preorder
* traversal of the Document
tree.
*
* @param tagname
* The name of the tag to match on. The special value "*" matches all
* tags.
* @return A new NodeList
object containing all the matched
* Elements
.
*/
public final NodeList getElementsByTagName(final String tagname) {
final NodeList list = document.getElementsByTagName(tagname);
return getXmlNodeList(list);
}
/**
* Returns a NodeList
of all the Elements
with
* a given local name and namespace URI in the order in which they are
* encountered in a preorder traversal of the Document
tree.
*
* @param namespaceURI
* The namespace URI of the elements to match on. The special value
* "*" matches all namespaces.
* @param localName
* The local name of the elements to match on. The special value "*"
* matches all local names.
* @return A new NodeList
object containing all the matched
* Elements
.
*/
public final NodeList getElementsByTagNameNS(final String namespaceURI,
final String localName) {
return getXmlNodeList(document.getElementsByTagNameNS(namespaceURI,
localName));
}
/**
* Get the XmlNode object corresponding to the node.
*
* @param node -
* Node to convert to an XmlNode
* @return XmlNode representing the node.
*/
protected final Node getXmlNode(final Node node) {
final XmlNodeFactory> factory = getXmlNodefactory();
return factory.getXmlNode(node);
}
/**
* Get the XmlNodeList object corresponding to the nodelist.
*
* @param nodeList -
* Node to convert to an XmlNodeList
* @return XmlNodeList representing the node.
*/
protected abstract NodeList getXmlNodeList(final NodeList nodeList);
/**
* The first child of this node.
*
* @return Node
*/
public final Node getFirstChild() {
return getXmlNode(document.getFirstChild());
}
/**
* The DOMImplementation
object that handles this document.
*
* @return DOMImplementation
*/
public final DOMImplementation getImplementation() {
return document.getImplementation();
}
/**
* The last child of this node.
*
* @return Node
*/
public final Node getLastChild() {
return getXmlNode(document.getLastChild());
}
/**
* Returns the local part of the qualified name of this node.
*
* @return String
*/
public final String getLocalName() {
return document.getLocalName();
}
/**
* The namespace URI of this node, or null
if it is
* unspecified.
*
* @return String
*/
public final String getNamespaceURI() {
if (document == null) {
return getDefaultNamespaceURI();
}
return document.getNamespaceURI();
}
/**
* Retrieves the default namespace.
* @return the default namespace, never null
.
* @since 0.7.5
*/
protected abstract String getDefaultNamespaceURI();
/**
* The node immediately following this node.
*
* @return Node
*/
public final Node getNextSibling() {
return getXmlNode(document.getNextSibling());
}
/**
* The name of this node, depending on its type; see the table above.
*
* @return String
*/
public final String getNodeName() {
return document.getNodeName();
}
/**
* A code representing the type of the underlying object, as defined above.
*
* @return short
*/
public final short getNodeType() {
return document.getNodeType();
}
/**
* The value of this node, depending on its type; see the table above.
*
* @return String
*/
public final String getNodeValue() {
return document.getNodeValue();
}
/**
* The Document
object associated with this node.
*
* @return Document
*/
public final Document getOwnerDocument() {
return document.getOwnerDocument();
}
/**
* The parent of this node.
*
* @return Node
*/
public final Node getParentNode() {
return getXmlNode(document.getParentNode());
}
/**
* The namespace prefix of this node, or null
if it is
* unspecified.
*
* @return String
*/
public final String getPrefix() {
return document.getPrefix();
}
/**
* The node immediately preceding this node.
*
* @return Node
*/
public final Node getPreviousSibling() {
return getXmlNode(document.getPreviousSibling());
}
/**
* Returns whether this node (if it is an element) has any attributes.
*
* @return true
if this node has any attributes,
* false
otherwise.
*/
public final boolean hasAttributes() {
return document.hasAttributes();
}
/**
* Returns whether this node has any children.
*
* @return true
if this node has any children,
* false
otherwise.
*/
public final boolean hasChildNodes() {
return document.hasChildNodes();
}
/**
* Imports a node from another document to this document.
*
* @param importedNode
* The node to import.
* @param deep
* If true
, recursively import the subtree under the
* specified node; if false
, import only the node
* itself, as explained above. This has no effect on
* Attr
, EntityReference
, and
* Notation
nodes.
* @return The imported node that belongs to this Document
.
*/
public final Node importNode(final Node importedNode, final boolean deep) {
return document.importNode(importedNode, deep);
}
/**
* An attribute specifying the encoding used for this document at the time
* of the parsing.
*
* @return String
*/
public final String getInputEncoding() {
return document.getInputEncoding();
}
/**
* An attribute specifying, as part of the XML
* declaration, the encoding of this document.
*
* @return String
*/
public final String getXmlEncoding() {
return document.getXmlEncoding();
}
/**
* An attribute specifying, as part of the XML
* declaration, whether this document is standalone.
*
* @return boolean
*/
public final boolean getXmlStandalone() {
return document.getXmlStandalone();
}
/**
* An attribute specifying, as part of the XML
* declaration, whether this document is standalone.
*
* @param xmlStandalone
* boolean
*/
public final void setXmlStandalone(final boolean xmlStandalone) {
document.setXmlStandalone(xmlStandalone);
}
/**
* An attribute specifying, as part of the XML
* declaration, the version number of this document.
*
* @return String
*/
public final String getXmlVersion() {
return document.getXmlVersion();
}
/**
* An attribute specifying, as part of the XML
* declaration, the version number of this document.
*
* @param xmlVersion
* String
*/
public final void setXmlVersion(final String xmlVersion) {
document.setXmlVersion(xmlVersion);
}
/**
* An attribute specifying whether error checking is enforced or not.
*
* @return boolean
*/
public final boolean getStrictErrorChecking() {
return document.getStrictErrorChecking();
}
/**
* An attribute specifying whether error checking is enforced or not.
*
* @param strictErrorChecking
* boolean
*/
public final void setStrictErrorChecking(
final boolean strictErrorChecking) {
document.setStrictErrorChecking(strictErrorChecking);
}
/**
* The location of the document or null
if undefined or if
* the Document
was created using
* DOMImplementation.createDocument
.
*
* @return String
*/
public final String getDocumentURI() {
return document.getDocumentURI();
}
/**
* The location of the document or null
if undefined or if
* the Document
was created using
* DOMImplementation.createDocument
.
*
* @param documentURI
* String
*/
public final void setDocumentURI(final String documentURI) {
document.setDocumentURI(documentURI);
}
/**
* Attempts to adopt a node from another document to this document.
*
* @param source
* The node to move into this document.
* @return The adopted node, or null
if this operation fails,
* such as when the source node comes from a different
* implementation.
*/
public final Node adoptNode(final Node source) {
return document.adoptNode(getRawNode(source));
}
/**
* The configuration used when Document.normalizeDocument()
* is invoked.
*
* @return DOMConfiguration
*/
public final DOMConfiguration getDomConfig() {
return document.getDomConfig();
}
/**
* This method acts as if the document was going through a save and load
* cycle, putting the document in a "normal" form.
*/
public final void normalizeDocument() {
document.normalizeDocument();
}
/**
* Rename an existing node of type ELEMENT_NODE
or
* ATTRIBUTE_NODE
.
*
* @param n
* The node to rename.
* @param namespaceURI
* The new namespace URI.
* @param qualifiedName
* The new qualified name.
* @return The renamed node. This is either the specified node or the new
* node that was created to replace the specified node.
*/
public final Node renameNode(final Node n, final String namespaceURI,
final String qualifiedName) {
return document.renameNode(getRawNode(n), namespaceURI, qualifiedName);
}
/**
* Inserts the node newChild
before the existing child node
* refChild
.
*
* @param newChild
* The node to insert.
* @param refChild
* The reference node, i.e., the node before which the new node must
* be inserted.
* @return The node being inserted.
*/
public final Node insertBefore(final Node newChild, final Node refChild) {
return document
.insertBefore(getRawNode(newChild), getRawNode(refChild));
}
/**
* Tests whether the DOM implementation implements a specific feature and
* that feature is supported by this node.
*
* @param feature
* The name of the feature to test. This is the same name which can
* be passed to the method hasFeature
on
* DOMImplementation
.
* @param version
* This is the version number of the feature to test. In Level 2,
* version 1, this is the string "2.0". If the version is not
* specified, supporting any version of the feature will cause the
* method to return true
.
* @return Returns true
if the specified feature is supported
* on this node, false
otherwise.
*/
public final boolean isSupported(final String feature,
final String version) {
return document.isSupported(feature, version);
}
/**
* Puts all Text
nodes in the full depth of the sub-tree
* underneath this Node
, including attribute nodes, into a
* "normal" form where only structure (e.g., elements, comments, processing
* instructions, CDATA sections, and entity references) separates
* Text
nodes, i.e., there are neither adjacent
* Text
nodes nor empty Text
nodes.
*
*/
public final void normalize() {
document.normalize();
}
/**
* Removes the child node indicated by oldChild
from the list
* of children, and returns it.
*
* @param oldChild
* The node being removed.
* @return The node removed.
*/
public final Node removeChild(final Node oldChild) {
return document.removeChild(getRawNode(oldChild));
}
/**
* Replaces the child node oldChild
with
* newChild
in the list of children, and returns the
* oldChild
node.
*
* @param newChild
* The new node to put in the child list.
* @param oldChild
* The node being replaced in the list.
* @return The node replaced.
*/
public final Node replaceChild(final Node newChild, final Node oldChild) {
return document
.replaceChild(getRawNode(newChild), getRawNode(oldChild));
}
/**
* The value of this node, depending on its type; see the table above.
*
* @param nodeValue
* String
*/
public final void setNodeValue(final String nodeValue) {
document.setNodeValue(nodeValue);
}
/**
* The namespace prefix of this node, or null
if it is
* unspecified.
*
* @param prefix
* String
*/
public final void setPrefix(final String prefix) {
document.setPrefix(prefix);
}
/**
* The absolute base URI of this node or null
if the
* implementation wasn't able to obtain an absolute URI.
*
* @return String
*/
public final String getBaseURI() {
return document.getBaseURI();
}
/**
* Compares the reference node, i.e.
*
* @param other
* The node to compare against the reference node.
* @return Returns how the node is positioned relatively to the reference
* node.
*/
public final short compareDocumentPosition(final Node other) {
return document.compareDocumentPosition(getRawNode(other));
}
/**
* This attribute returns the text content of this node and its descendants.
*
* @return String
*/
public final String getTextContent() {
return document.getTextContent();
}
/**
* This attribute returns the text content of this node and its descendants.
*
* @param textContent
* String
*/
public final void setTextContent(final String textContent) {
document.setTextContent(textContent);
}
/**
* Returns whether this node is the same node as the given one.
*
* @param other
* The node to test against.
* @return Returns true
if the nodes are the same,
* false
otherwise.
*/
public final boolean isSameNode(final Node other) {
return document.isSameNode(getRawNode(other));
}
/**
* Look up the prefix associated to the given namespace URI, starting from
* this node.
*
* @param namespaceURI
* The namespace URI to look for.
* @return Returns an associated namespace prefix if found or
* null
if none is found. If more than one prefix are
* associated to the namespace prefix, the returned namespace prefix
* is implementation dependent.
*/
public final String lookupPrefix(final String namespaceURI) {
return document.lookupPrefix(namespaceURI);
}
/**
* This method checks if the specified namespaceURI
is the
* default namespace or not.
*
* @param namespaceURI
* The namespace URI to look for.
* @return Returns true
if the specified
* namespaceURI
is the default namespace,
* false
otherwise.
*/
public final boolean isDefaultNamespace(final String namespaceURI) {
return document.isDefaultNamespace(namespaceURI);
}
/**
* Look up the namespace URI associated to the given prefix, starting from
* this node.
*
* @param prefix
* The prefix to look for. If this parameter is null
,
* the method will return the default namespace URI if any.
* @return Returns the associated namespace URI or null
if
* none is found.
*/
public final String lookupNamespaceURI(final String prefix) {
return document.lookupNamespaceURI(prefix);
}
/**
* Tests whether two nodes are equal.
*
* @param arg
* The node to compare equality with.
* @return Returns true
if the nodes are equal,
* false
otherwise.
*/
public final boolean isEqualNode(final Node arg) {
return document.isEqualNode(arg);
}
/**
* This method returns a specialized object which implements the specialized
* APIs of the specified feature and version, as specified in .
*
* @param feature
* The name of the feature requested. Note that any plus sign "+"
* prepended to the name of the feature will be ignored since it is
* not significant in the context of this method.
* @param version
* This is the version number of the feature to test.
* @return Returns an object which implements the specialized APIs of the
* specified feature and version, if any, or null
if
* there is no object which implements interfaces associated with
* that feature. If the DOMObject
returned by this
* method implements the Node
interface, it must
* delegate to the primary core Node
and not return
* results inconsistent with the primary core Node
* such as attributes, childNodes, etc.
*/
public final Object getFeature(final String feature, final String version) {
return document.getFeature(feature, version);
}
/**
* Associate an object to a key on this node.
*
* @param key
* The key to associate the object to.
* @param data
* The object to associate to the given key, or null
* to remove any existing association to that key.
* @param handler
* The handler to associate to that key, or null
.
* @return Returns the DOMUserData
previously associated to
* the given key on this node, or null
if there was
* none.
*/
public final Object setUserData(final String key, final Object data,
final UserDataHandler handler) {
return document.setUserData(key, data, handler);
}
/**
* Retrieves the object associated to a key on a this node.
*
* @param key
* The key the object is associated to.
* @return Returns the DOMUserData
associated to the given
* key on this node, or null
if there was none.
*/
public final Object getUserData(final String key) {
return document.getUserData(key);
}
/**
* Returns the contents of this object as an XML formatted string.
*
* @return XML representation of this object.
*
* @exception IOException
* Error writing to the writer.
*/
public final String toXml()
throws IOException {
final ByteArrayOutputStream out = new ByteArrayOutputStream();
final Result result = new StreamResult(out);
final TransformerFactory transformerFactory =
TransformerFactory.newInstance();
try {
final Transformer transformer = transformerFactory.newTransformer();
final String encoding = System.getProperty("jvoicexml.xml.encoding",
"UTF-8");
transformer.setOutputProperty(OutputKeys.ENCODING, encoding);
transformer.setOutputProperty(OutputKeys.STANDALONE, "yes");
final DocumentType type = getDoctype();
if (type != null) {
transformer.setOutputProperty(OutputKeys.DOCTYPE_PUBLIC,
type.getPublicId());
transformer.setOutputProperty(OutputKeys.DOCTYPE_SYSTEM,
type.getSystemId());
}
final Source source = new DOMSource(document);
transformer.transform(source, result);
return out.toString(encoding);
} catch (TransformerException e) {
throw new IOException(e.getMessage(), e);
}
}
/**
* {@inheritDoc}
*
* Creates a representation as an XML string. If this is not possible
* for some reason, the conventional {@link Object#toString()} creation
* is used.
*
* @since 0.3
*/
@Override
public final String toString() {
try {
return toXml();
} catch (java.io.IOException ioe) {
return super.toString();
}
}
/**
* Get the raw node encapsulated by the specified node. If the specified
* node is a raw node then it is returned.
*
* @param arg
* The node that may be wrapping a raw node.
* @return The raw node.
*/
private Node getRawNode(final Node arg) {
final Node rawNode;
if (arg instanceof VoiceXmlNode) {
final VoiceXmlNode voiceXmlNode = (VoiceXmlNode) arg;
rawNode = voiceXmlNode.getNode();
} else {
rawNode = arg;
}
return rawNode;
}
/**
* Writes the state of the object for its particular class so that the
* corresponding {@link #readObject(java.io.ObjectInputStream)}
* method can restore it.
* @param out the stream to write to
* @throws IOException
* if an error occurs while writing to the stream
*/
private void writeObject(final ObjectOutputStream out)
throws IOException {
final ByteArrayOutputStream buffer = new ByteArrayOutputStream();
final Result result = new StreamResult(buffer);
final TransformerFactory transformerFactory =
TransformerFactory.newInstance();
try {
final Transformer transformer = transformerFactory.newTransformer();
final String encoding = System.getProperty("jvoicexml.xml.encoding",
"UTF-8");
transformer.setOutputProperty(OutputKeys.ENCODING, encoding);
final Source source = new DOMSource(this);
transformer.transform(source, result);
} catch (TransformerException e) {
throw new IOException(e.getMessage(), e);
}
out.writeLong(buffer.size());
out.write(buffer.toByteArray());
}
/**
* Reads from the stream and restores the classes fields.
* @param in the stream to read from
* @throws IOException
* if an error occurs while reading from the stream
* @throws ClassNotFoundException
* if a dependent class could not be found
*/
private void readObject(final ObjectInputStream in)
throws IOException, ClassNotFoundException {
final int size = (int) in.readLong();
final byte[] buffer = new byte[size];
int num = 0;
do {
num += in.read(buffer, num, size - num);
} while (num < size);
final ByteArrayInputStream stream = new ByteArrayInputStream(buffer);
final InputSource source = new InputSource(stream);
final DocumentBuilderFactory factory =
DocumentBuilderFactory.newInstance();
factory.setNamespaceAware(true);
// Configure the factory to ignore comments
factory.setIgnoringComments(true);
try {
final DocumentBuilder builder = factory.newDocumentBuilder();
document = builder.parse(source);
} catch (SAXException e) {
throw new IOException(e.getMessage(), e);
} catch (ParserConfigurationException e) {
throw new IOException(e.getMessage(), e);
}
}
}