org.dom4j.io.DOMSAXContentHandler Maven / Gradle / Ivy
Go to download
Show more of this group Show more artifacts with this name
Show all versions of dom4j Show documentation
Show all versions of dom4j Show documentation
flexible XML framework for Java
/*
* Copyright 2001-2005 (C) MetaStuff, Ltd. All Rights Reserved.
*
* This software is open source.
* See the bottom of this file for the licence.
*/
package org.dom4j.io;
import java.lang.reflect.Method;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import org.dom4j.Branch;
import org.dom4j.Document;
import org.dom4j.Element;
import org.dom4j.Namespace;
import org.dom4j.QName;
import org.dom4j.dom.DOMAttribute;
import org.dom4j.dom.DOMCDATA;
import org.dom4j.dom.DOMComment;
import org.dom4j.dom.DOMDocumentFactory;
import org.dom4j.dom.DOMElement;
import org.dom4j.dom.DOMText;
import org.dom4j.tree.NamespaceStack;
import org.w3c.dom.ProcessingInstruction;
import org.xml.sax.Attributes;
import org.xml.sax.EntityResolver;
import org.xml.sax.InputSource;
import org.xml.sax.Locator;
import org.xml.sax.SAXException;
import org.xml.sax.SAXParseException;
import org.xml.sax.ext.LexicalHandler;
import org.xml.sax.ext.Locator2;
import org.xml.sax.helpers.DefaultHandler;
/**
*
* SAXContentHandler
builds W3C DOM object via SAX events.
*
* @author James Strachan
* @author Todd Wolff
*
*
*/
public class DOMSAXContentHandler extends DefaultHandler implements LexicalHandler {
/** The factory used to create new Document
instances */
private DOMDocumentFactory documentFactory;
/** The document that is being built */
private Document document;
/** stack of Element
objects */
private ElementStack elementStack;
/** stack of Namespace
and QName
objects */
private NamespaceStack namespaceStack;
/** the Locator */
private Locator locator;
/** Flag used to indicate that we are inside a CDATA section */
private boolean insideCDATASection;
/**
* buffer to hold contents of cdata section across multiple characters
* events
*/
private StringBuffer cdataText;
/** The number of namespaces that are declared in the current scope */
private int declaredNamespaceIndex;
private InputSource inputSource;
/** The current element we are on */
private Element currentElement;
/** The entity resolver */
private EntityResolver entityResolver;
/** Whether adjacent text nodes should be merged */
private boolean mergeAdjacentText = false;
/** Have we added text to the buffer */
private boolean textInTextBuffer = false;
/** Should we ignore comments */
private boolean ignoreComments = false;
/** Buffer used to concatenate text together */
private StringBuffer textBuffer;
/** Holds value of property stripWhitespaceText. */
private boolean stripWhitespaceText = false;
public DOMSAXContentHandler() {
this((DOMDocumentFactory)DOMDocumentFactory.getInstance());
}
public DOMSAXContentHandler(DOMDocumentFactory documentFactory) {
this.documentFactory = documentFactory;
this.elementStack = createElementStack();
this.namespaceStack = new NamespaceStack(documentFactory);
}
/**
* Retrieves w3c document object built via generated sax events.
*
* @return the document that has been or is being built
*/
public org.w3c.dom.Document getDocument() {
if (document == null) {
document = createDocument();
}
return (org.w3c.dom.Document)document;
}
// ContentHandler interface
// -------------------------------------------------------------------------
public void setDocumentLocator(Locator documentLocator) {
this.locator = documentLocator;
}
public void processingInstruction(String target, String data)
throws SAXException {
if (mergeAdjacentText && textInTextBuffer) {
completeCurrentTextNode();
}
ProcessingInstruction pi = (ProcessingInstruction)documentFactory.createProcessingInstruction(target, data);
if (currentElement != null) {
((org.w3c.dom.Element)currentElement).appendChild(pi);
} else {
getDocument().appendChild(pi);
}
}
public void startPrefixMapping(String prefix, String uri)
throws SAXException {
namespaceStack.push(prefix, uri);
}
public void endPrefixMapping(String prefix) throws SAXException {
namespaceStack.pop(prefix);
declaredNamespaceIndex = namespaceStack.size();
}
public void startDocument() throws SAXException {
document = null;
currentElement = null;
elementStack.clear();
namespaceStack.clear();
declaredNamespaceIndex = 0;
if (mergeAdjacentText && (textBuffer == null)) {
textBuffer = new StringBuffer();
}
textInTextBuffer = false;
}
public void endDocument() throws SAXException {
namespaceStack.clear();
elementStack.clear();
currentElement = null;
textBuffer = null;
}
public void startElement(String namespaceURI, String localName,
String qualifiedName, Attributes attributes) throws SAXException {
if (mergeAdjacentText && textInTextBuffer) {
completeCurrentTextNode();
}
QName qName = namespaceStack.getQName(namespaceURI, localName,
qualifiedName);
Branch branch = currentElement;
if (branch == null) {
branch = (org.dom4j.Document)getDocument();
}
Element element = new DOMElement(qName);
branch.add(element);
// add all declared namespaces
addDeclaredNamespaces(element);
// now lets add all attribute values
addAttributes(element, attributes);
elementStack.pushElement(element);
currentElement = element;
}
public void endElement(String namespaceURI, String localName, String qName)
throws SAXException {
if (mergeAdjacentText && textInTextBuffer) {
completeCurrentTextNode();
}
elementStack.popElement();
currentElement = elementStack.peekElement();
}
public void characters(char[] ch, int start, int end) throws SAXException {
if (end == 0) {
return;
}
if (currentElement != null) {
if (insideCDATASection) {
if (mergeAdjacentText && textInTextBuffer) {
completeCurrentTextNode();
}
cdataText.append(new String(ch, start, end));
} else {
if (mergeAdjacentText) {
textBuffer.append(ch, start, end);
textInTextBuffer = true;
} else {
DOMText text = new DOMText(new String(ch, start, end));
((DOMElement)currentElement).add(text);
}
}
}
}
// ErrorHandler interface
// -------------------------------------------------------------------------
/**
* This method is called when a warning occurs during the parsing of the
* document. This method does nothing.
*
* @param exception
* DOCUMENT ME!
*
* @throws SAXException
* DOCUMENT ME!
*/
public void warning(SAXParseException exception) throws SAXException {
// ignore warnings by default
}
/**
* This method is called when an error is detected during parsing such as a
* validation error. This method rethrows the exception
*
* @param exception
* DOCUMENT ME!
*
* @throws SAXException
* DOCUMENT ME!
*/
public void error(SAXParseException exception) throws SAXException {
throw exception;
}
/**
* This method is called when a fatal error occurs during parsing. This
* method rethrows the exception
*
* @param exception
* DOCUMENT ME!
*
* @throws SAXException
* DOCUMENT ME!
*/
public void fatalError(SAXParseException exception) throws SAXException {
throw exception;
}
// LexicalHandler interface
// -------------------------------------------------------------------------
public void startDTD(String name, String publicId, String systemId)
throws SAXException {
// not supported
}
public void endDTD() throws SAXException {
// not supported
}
public void startEntity(String name) throws SAXException {
// not supported
}
public void endEntity(String name) throws SAXException {
// not supported
}
public void startCDATA() throws SAXException {
insideCDATASection = true;
cdataText = new StringBuffer();
}
public void endCDATA() throws SAXException {
insideCDATASection = false;
DOMCDATA cdata = new DOMCDATA(cdataText.toString());
((DOMElement)currentElement).add(cdata);
}
public void comment(char[] ch, int start, int end) throws SAXException {
if (!ignoreComments) {
if (mergeAdjacentText && textInTextBuffer) {
completeCurrentTextNode();
}
String text = new String(ch, start, end);
if (text.length() > 0) {
DOMComment domComment = new DOMComment(text);
if (currentElement != null) {
((DOMElement)currentElement).add(domComment);
} else {
getDocument().appendChild(domComment);
}
}
}
}
// Properties
// -------------------------------------------------------------------------
public ElementStack getElementStack() {
return elementStack;
}
public void setElementStack(ElementStack elementStack) {
this.elementStack = elementStack;
}
public EntityResolver getEntityResolver() {
return entityResolver;
}
public void setEntityResolver(EntityResolver entityResolver) {
this.entityResolver = entityResolver;
}
public InputSource getInputSource() {
return inputSource;
}
public void setInputSource(InputSource inputSource) {
this.inputSource = inputSource;
}
/**
* Returns whether adjacent text nodes should be merged together.
*
* @return Value of property mergeAdjacentText.
*/
public boolean isMergeAdjacentText() {
return mergeAdjacentText;
}
/**
* Sets whether or not adjacent text nodes should be merged together when
* parsing.
*
* @param mergeAdjacentText
* New value of property mergeAdjacentText.
*/
public void setMergeAdjacentText(boolean mergeAdjacentText) {
this.mergeAdjacentText = mergeAdjacentText;
}
/**
* Sets whether whitespace between element start and end tags should be
* ignored
*
* @return Value of property stripWhitespaceText.
*/
public boolean isStripWhitespaceText() {
return stripWhitespaceText;
}
/**
* Sets whether whitespace between element start and end tags should be
* ignored.
*
* @param stripWhitespaceText
* New value of property stripWhitespaceText.
*/
public void setStripWhitespaceText(boolean stripWhitespaceText) {
this.stripWhitespaceText = stripWhitespaceText;
}
/**
* Returns whether we should ignore comments or not.
*
* @return boolean
*/
public boolean isIgnoreComments() {
return ignoreComments;
}
/**
* Sets whether we should ignore comments or not.
*
* @param ignoreComments
* whether we should ignore comments or not.
*/
public void setIgnoreComments(boolean ignoreComments) {
this.ignoreComments = ignoreComments;
}
// Implementation methods
// -------------------------------------------------------------------------
protected void completeCurrentTextNode() {
if (stripWhitespaceText) {
boolean whitespace = true;
for (int i = 0, size = textBuffer.length(); i < size; i++) {
if (!Character.isWhitespace(textBuffer.charAt(i))) {
whitespace = false;
break;
}
}
if (!whitespace) {
DOMText domText = new DOMText(textBuffer.toString());
((DOMElement)currentElement).add(domText);
}
} else {
DOMText domText = new DOMText(textBuffer.toString());
((DOMElement)currentElement).add(domText);
}
textBuffer.setLength(0);
textInTextBuffer = false;
}
protected Document createDocument() {
String encoding = getEncoding();
Document doc = documentFactory.createDocument(encoding);
// set the EntityResolver
doc.setEntityResolver(entityResolver);
if (inputSource != null) {
doc.setName(inputSource.getSystemId());
}
return doc;
}
private String getEncoding() {
if (locator == null) {
return null;
}
if (locator instanceof Locator2) {
return ((Locator2) locator).getEncoding();
}
// couldn't determine encoding, returning null...
return null;
}
protected void addDeclaredNamespaces(Element element) {
for (int size = namespaceStack.size(); declaredNamespaceIndex < size;
declaredNamespaceIndex++) {
Namespace namespace = namespaceStack
.getNamespace(declaredNamespaceIndex);
String attributeName = attributeNameForNamespace(namespace);
((DOMElement)element).setAttribute(attributeName, namespace.getURI());
}
}
protected void addAttributes(Element element, Attributes attributes) {
int size = attributes.getLength();
for (int i = 0; i < size; i++) {
String attributeQName = attributes.getQName(i);
if (!attributeQName.startsWith("xmlns")) {
String attributeURI = attributes.getURI(i);
String attributeLocalName = attributes.getLocalName(i);
String attributeValue = attributes.getValue(i);
QName qName = namespaceStack.getAttributeQName(
attributeURI, attributeLocalName, attributeQName);
DOMAttribute domAttribute = new DOMAttribute(qName, attributeValue);
((DOMElement)element).setAttributeNode(domAttribute);
}
}
}
protected ElementStack createElementStack() {
return new ElementStack();
}
protected String attributeNameForNamespace(Namespace namespace) {
String xmlns = "xmlns";
String prefix = namespace.getPrefix();
if (prefix.length() > 0) {
return xmlns + ":" + prefix;
}
return xmlns;
}
}
/*
* Redistribution and use of this software and associated documentation
* ("Software"), with or without modification, are permitted provided that the
* following conditions are met:
*
* 1. Redistributions of source code must retain copyright statements and
* notices. Redistributions must also contain a copy of this document.
*
* 2. Redistributions in binary form must reproduce the above copyright notice,
* this list of conditions and the following disclaimer in the documentation
* and/or other materials provided with the distribution.
*
* 3. The name "DOM4J" must not be used to endorse or promote products derived
* from this Software without prior written permission of MetaStuff, Ltd. For
* written permission, please contact [email protected].
*
* 4. Products derived from this Software may not be called "DOM4J" nor may
* "DOM4J" appear in their names without prior written permission of MetaStuff,
* Ltd. DOM4J is a registered trademark of MetaStuff, Ltd.
*
* 5. Due credit should be given to the DOM4J Project - http://www.dom4j.org
*
* THIS SOFTWARE IS PROVIDED BY METASTUFF, LTD. AND CONTRIBUTORS ``AS IS'' AND
* ANY EXPRESSED OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
* ARE DISCLAIMED. IN NO EVENT SHALL METASTUFF, LTD. OR ITS CONTRIBUTORS BE
* LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
* CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
* SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
* INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
* CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
* ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
* POSSIBILITY OF SUCH DAMAGE.
*
* Copyright 2001-2005 (C) MetaStuff, Ltd. All Rights Reserved.
*/
© 2015 - 2025 Weber Informatics LLC | Privacy Policy