cziegeler 02/01/18 04:19:19
Modified: src/java/org/apache/cocoon/transformation
AbstractDOMTransformer.java
src/java/org/apache/cocoon/xml/dom DOMBuilder.java
Log:
Refactored DOMBuilder: now using provided jaxp features instead of reinventing the
wheel
Revision Changes Path
1.2 +0 -11
xml-cocoon2/src/java/org/apache/cocoon/transformation/AbstractDOMTransformer.java
Index: AbstractDOMTransformer.java
===================================================================
RCS file:
/home/cvs/xml-cocoon2/src/java/org/apache/cocoon/transformation/AbstractDOMTransformer.java,v
retrieving revision 1.1
retrieving revision 1.2
diff -u -r1.1 -r1.2
--- AbstractDOMTransformer.java 3 Jan 2002 12:31:20 -0000 1.1
+++ AbstractDOMTransformer.java 18 Jan 2002 12:19:19 -0000 1.2
@@ -56,8 +56,6 @@
protected ComponentManager manager;
public AbstractDOMTransformer() {
- // Set the factory later, when we have a Component Manager to get a
- // Parser from
super();
super.listener = this;
}
@@ -67,14 +65,6 @@
*/
public void compose(ComponentManager manager) {
this.manager = manager;
- // Get a parser and use it as a DOM factory
- try {
- log.debug("Looking up " + Parser.ROLE);
- Parser p = (Parser)manager.lookup(Parser.ROLE);
- super.factory = p;
- } catch (Exception e) {
- log.error("Could not find component", e);
- }
}
/**
@@ -169,6 +159,5 @@
* dispose
*/
public void dispose() {
- if(super.factory != null) manager.release((Component)super.factory);
}
}
1.2 +67 -496 xml-cocoon2/src/java/org/apache/cocoon/xml/dom/DOMBuilder.java
Index: DOMBuilder.java
===================================================================
RCS file: /home/cvs/xml-cocoon2/src/java/org/apache/cocoon/xml/dom/DOMBuilder.java,v
retrieving revision 1.1
retrieving revision 1.2
diff -u -r1.1 -r1.2
--- DOMBuilder.java 3 Jan 2002 12:31:23 -0000 1.1
+++ DOMBuilder.java 18 Jan 2002 12:19:19 -0000 1.2
@@ -8,569 +8,140 @@
package org.apache.cocoon.xml.dom;
-import org.apache.avalon.framework.logger.Loggable;
-import org.apache.cocoon.xml.NamespacesTable;
-import org.apache.cocoon.xml.XMLConsumer;
-import org.apache.log.Logger;
-import org.w3c.dom.*;
-import org.xml.sax.Attributes;
-import org.xml.sax.Locator;
+import org.apache.cocoon.xml.AbstractXMLPipe;
import org.xml.sax.SAXException;
-
-import java.util.Vector;
+import org.w3c.dom.Document;
+import org.w3c.dom.Node;
+import javax.xml.transform.dom.DOMResult;
+import javax.xml.transform.sax.SAXTransformerFactory;
+import javax.xml.transform.sax.TransformerHandler;
/**
* The <code>DOMBuilder</code> is a utility class that will generate a W3C
* DOM Document from SAX events.
*
- * @author <a href="mailto:[EMAIL PROTECTED]">Pierpaolo Fumagalli</a>
- * (Apache Software Foundation, Exoffice Technologies)
- * @version CVS $Revision: 1.1 $ $Date: 2002/01/03 12:31:23 $
+ * @author <a href="mailto:[EMAIL PROTECTED]">Carsten Ziegeler</a>
+ * @version CVS $Revision: 1.2 $ $Date: 2002/01/18 12:19:19 $
*/
-public class DOMBuilder implements XMLConsumer, Loggable {
- protected Logger log;
- /** The document was not started */
- private static final int S_AVAIL=0;
- /** State between startDTD() and endDTD() */
- private static final int S_DTD=1;
- /** State between startDocument() and endDocument() */
- private static final int S_DOC=2;
- /** State between the first startElement() and the last endElement() */
- private static final int S_BODY=3;
- /** State between the first startElement() and the last endElement() */
- private static final int S_CDATA=4;
- /** The state names (used by Location to output better error messages */
- private static final String stateName[]={
- "Available", "DTD Processing", "Document", "Body", "CDATA Section"
- };
-
- /** The current state */
- private int state=S_AVAIL;
- /** The locator */
- private Locator locator=null;
+public class DOMBuilder
+extends AbstractXMLPipe {
+
+ /** The transformer factory shared by all instances */
+ protected static final SAXTransformerFactory factory =
(SAXTransformerFactory)SAXTransformerFactory.newInstance();
+
/** The listener */
- protected Listener listener=null;
- /** The namespaces table */
- private NamespacesTable namespaces=null;
- /** The current document */
- private Document document=null;
- /** The current node */
- private Node current=null;
- /** The document name (tag name of the root element) */
- private String name=null;
- /** The vector of namespaces declarations to include in the next element */
- private Vector undecl=new Vector();
+ protected Listener listener;
- /** The document factory */
- protected DOMFactory factory=null;
+ /** The result */
+ protected DOMResult result;
/**
* Construct a new instance of this TreeGenerator.
*/
- protected DOMBuilder() {
- this(null,null);
- }
-
- public void setLogger(Logger logger) {
- if (this.log == null) {
- this.log = logger;
- }
+ public DOMBuilder() {
+ this( (Listener)null, (Node)null );
}
/**
* Construct a new instance of this TreeGenerator.
+ * @deprecated Use DOMBuilder() instead.
*/
public DOMBuilder(DOMFactory factory) {
- this(factory,null);
+ this( (Listener)null, (Node)null );
}
/**
* Construct a new instance of this TreeGenerator.
*/
- public DOMBuilder(DOMFactory factory, Listener listener) {
- super();
- this.factory=factory;
- this.listener=listener;
- }
-
- /**
- * Constructs a new instance that appends nodes to the given parent node.<br/>
- * Note : you cannot use a <code>Listener<code> when appending to a
- * <code>Node</code>, because the notification occurs at
<code>endDocument()</code>
- * which does not happen here.
- */
-
- public DOMBuilder(Node parentNode) {
- // Set the document as the owner of this node
- this.document = parentNode.getOwnerDocument();
- // Create a namespace table
- this.namespaces=new NamespacesTable();
- // Set the current node
- this.current = parentNode;
- // Go directly to BODY state
- this.state = S_BODY;
- }
-
- /** * Return the newly built Document.
- */
- public Document getDocument() {
- return(this.document);
- }
-
- /**
- * Set the SAX Document Locator.
- *
- * @param loc The SAX Locator.
- */
- public void setDocumentLocator (Locator loc) {
- this.locator=loc;
- }
-
- /**
- * Receive notification of the beginning of a document.
- *
- * @exception SAXException If this method was not called appropriately.
- */
- public void startDocument()
- throws SAXException {
- if(state!=S_AVAIL) throw new SAXException("Invalid state"+location());
- // Create the namespaces table
- this.namespaces=new NamespacesTable();
- // Create a new Document empty document object
- this.document=this.factory.newDocument();
- // Set the current node
- this.current=this.document;
- // Do a state change
- state=S_DOC;
- }
-
- /**
- * Receive notification of the beginning of a document.
- *
- * @exception SAXException If this method was not called appropriately.
- */
- public void endDocument ()
- throws SAXException {
- if(state!=S_DOC) throw new SAXException("Invalid state"+location());
- // Check if the current element is the document
- if(this.document!=this.current)
- throw new SAXException("Invalid current node"+location());
- // Reset the current node and the document name
- this.current=null;
- this.name=null;
- // Do a state change and reset the DTD flag
- state=S_AVAIL;
- // Notify the listener
- this.notify(this.document);
+ public DOMBuilder( Listener listener ) {
+ this(listener, null);
}
/**
- * Report the start of DTD declarations, if any.
- *
- * @param name The document type name.
- * @param publicId The declared public identifier for the external DTD
- * subset, or null if none was declared.
- * @param systemId The declared system identifier for the external DTD
- * subset, or null if none was declared.
- * @exception SAXException If this method was not called appropriately.
+ * Construct a new instance of this TreeGenerator.
+ * @deprecated Use DOMBuilder(listener) instead.
*/
- public void startDTD(String name, String publicId, String systemId)
- throws SAXException {
- // This method can be called only at DOCUMENT level
- if(state!=S_DOC) throw new SAXException("Invalid state"+location());
- // Check wether this method was already invoked
- if(this.name!=null)
- throw new SAXException("Duplicate DTD definition"+location());
- // Remember the specified document name
- this.name=name;
- // Recreate the document element
- Document doc=this.factory.newDocument(name,publicId,systemId);
- // Copy the old document root PIs
- NodeList list=this.document.getChildNodes();
- for (int x=0; x<list.getLength(); x++) {
- if (list.item(x).getNodeType()!=Node.DOCUMENT_TYPE_NODE)
- doc.appendChild(doc.importNode(list.item(x),true));
- }
- // Declare the new document as the new real document
- this.document=doc;
- this.current=this.document;
- // Do a state change
- state=S_DTD;
+ public DOMBuilder( DOMFactory factory, Listener listener ) {
+ this(listener, null);
}
/**
- * Report the end of DTD declarations.
- *
- * @param chars The characters from the XML document.
- * @param start The start position in the array.
- * @param len The number of characters to read from the array.
- * @exception SAXException If this method was not called appropriately.
+ * Construct a new instance of this TreeGenerator.
+ * @deprecated Use DOMBuilder(listener, parentNode) instead.
*/
- public void endDTD()
- throws SAXException {
- // This method can be called only at DTD level
- if(state!=S_DTD) throw new SAXException("Invalid state"+location());
- // Do a state change
- state=S_DOC;
+ public DOMBuilder( DOMFactory domFactory, Listener listener, Node parentNode ) {
+ this(listener, parentNode);
}
/**
- * Receive notification of the beginning of an element.
- *
- * @parameter uri The Namespace URI, or the empty string if the element
- * has no Namespace URI or if Namespace processing is not
- * being performed.
- * @parameter loc The local name (without prefix), or the empty
- * string if Namespace processing is not being
- * performed.
- * @parameter raw The raw XML 1.0 name (with prefix), or the empty
- * string if raw names are not available.
- * @parameter a The attributes attached to the element. If there are no
- * attributes, it shall be an empty Attributes object.
- * @exception SAXException If this method was not called appropriately.
+ * Construct a new instance of this TreeGenerator.
*/
- public void startElement(String uri, String loc, String raw, Attributes a)
- throws SAXException {
- NamespacesTable.Name n=this.namespaces.resolve(uri,raw,null,loc);
- // Check if this is we are defining the document root element
- if(state==S_DOC) {
- // Check if the DTD was specified
- if (this.name!=null) {
- // Check that this root element is equal to the one specified
- // in the DTD
- if (!this.name.equals(n.getQName()))
- throw new SAXException("The name specified in the DTD '"+
- this.name+"' differs from the root "+
- "element name '"+n.getQName()+
- "'"+location());
- // Recreate the document since no DTD was specified
+ public DOMBuilder( Listener listener, Node parentNode ) {
+ super();
+ this.listener = listener;
+ try {
+ TransformerHandler handler = factory.newTransformerHandler();
+ this.setContentHandler(handler);
+ this.setLexicalHandler(handler);
+ if (parentNode != null) {
+ this.result = new DOMResult( parentNode );
} else {
- /* DISABLED pending us tracking down what's causing document
- * hierachy errors when we do this. This may well break people's
- * code, but hopefully that will provide some enlightenment
- * anyhow.
- // Recreate the document element
- Document doc=this.factory.newDocument(n.getQName());
- // Copy the old document root PIs
- NodeList list=this.document.getChildNodes();
- for (int x=0; x<list.getLength(); x++) {
- if (list.item(x).getNodeType()!=Node.DOCUMENT_TYPE_NODE)
- doc.appendChild(doc.importNode(list.item(x),true));
+ this.result = new DOMResult();
}
- // Declare the new document as the new real document
- this.document=doc;
- */
- this.current=this.document;
- }
- // Change the state before continuing
- state=S_BODY;
- }
- // Now that we initialized the root element we can perform the standard
- // element check
- if(state!=S_BODY) throw new SAXException("Invalid state"+location());
- // Create the Element node
- Element e=this.document.createElementNS(("".equals(n.getUri()) ? null :
n.getUri()),n.getQName());
- // Process all attributes, leave out namespace attributes
- for(int x=0;x<a.getLength();x++) {
- String auri=a.getURI(x);
- String aloc=a.getLocalName(x);
- String araw=a.getQName(x);
- String aval=a.getValue(x);
- if (araw.startsWith("xmlns:")==false && araw.equals("xmlns")==false) {
- NamespacesTable.Name k=this.namespaces.resolve(auri,araw,null,aloc);
- // Set the attribute into the element
- auri=k.getPrefix().length()==0 ? null : k.getUri();
- e.setAttributeNS(auri,k.getQName(),aval);
- }
- }
- // Append the xmlns... attributes
- if (this.undecl.size()>0) {
- for (int x=0; x<this.undecl.size(); x++) {
- NamespacesTable.Declaration dec=null;
- dec=(NamespacesTable.Declaration)this.undecl.elementAt(x);
- String aname="xmlns";
- if (dec.getPrefix().length()>0) aname="xmlns:"+dec.getPrefix();
- e.setAttributeNS("http://www.w3.org/2000/xmlns/",
aname,dec.getUri());
- }
- this.undecl.clear();
+ handler.setResult(this.result);
+ } catch (javax.xml.transform.TransformerException local) {
+ throw new RuntimeException("Fatal-Error: Unable to get transformer
handler");
}
- // Append this element to the parent and declare it current
- this.current.appendChild(e);
- this.current=e;
- }
-
- /**
- * Receive notification of the end of an element.
- *
- * @parameter uri The Namespace URI, or the empty string if the element
- * has no Namespace URI or if Namespace processing is not
- * being performed.
- * @parameter local The local name (without prefix), or the empty
- * string if Namespace processing is not being
- * performed.
- * @parameter raw The raw XML 1.0 name (with prefix), or the empty
- * string if raw names are not available.
- * @exception SAXException If this method was not called appropriately.
- */
- public void endElement (String uri, String loc, String raw)
- throws SAXException {
- if(state!=S_BODY) throw new SAXException("Invalid state"+location());
-
- // Check if the current node is an element
- if (this.current.getNodeType()!=Node.ELEMENT_NODE)
- throw new SAXException("Current node is not an element"+location());
-
- // Check if the current element has the same tag name of this event
- NamespacesTable.Name n=this.namespaces.resolve(uri,raw,null,loc);
- String oldname=((Element)this.current).getTagName();
- if (!oldname.equals(n.getQName()))
- throw new SAXException("Element end tag name '"+n.getQName()+
- "' differs from start tag name '"+
- oldname+"'"+location());
- // Restore the old node as current
- this.current=this.current.getParentNode();
- if (this.current==null) throw new SAXException("No parent"+location());
- // Update the state if the current node is the document
- if (this.current==this.document) state=S_DOC;
}
/**
- * Begin the scope of a prefix-URI Namespace mapping.
- *
- * @param pre The Namespace prefix being declared.
- * @param uri The Namespace URI the prefix is mapped to.
- * @exception SAXException If this method was not called appropriately.
- */
- public void startPrefixMapping(String prefix, String uri)
- throws SAXException {
- // This method can only called at DOCUMENT or BODY levels
- if((state<S_DOC)||(state>S_BODY))
- throw new SAXException("Invalid state"+location());
- // Insert this namespace in tables avoiding duplicates
- this.undecl.addElement(this.namespaces.addDeclaration(prefix,uri));
- }
-
- /**
- * End the scope of a prefix-URI mapping.
- *
- * @param prefix The Namespace prefix that was being mapped.
- */
- public void endPrefixMapping(String prefix)
- throws SAXException {
- // This method can only called at DOCUMENT or BODY levels
- if((state<S_DOC)||(state>S_BODY))
- throw new SAXException("Invalid state"+location());
- // Check if the namespace we're asked to remove was declared
- if (this.namespaces.removeDeclaration(prefix)==null)
- throw new SAXException("Prefix \""+prefix+"\" never declared"+
- location());
- }
-
- /**
- * Report the start of a CDATA section.
- *
- * @exception SAXException If this method was not called appropriately.
- */
- public void startCDATA()
- throws SAXException {
- // This method can only called at BODY level
- if(state!=S_BODY) throw new SAXException("Invalid state"+location());
- CDATASection cdata=this.document.createCDATASection("");
- // Set the CDATASection as the current element
- this.current.appendChild(cdata);
- this.current=cdata;
- // Do a state change
- state=S_CDATA;
- }
-
- /**
- * Report the end of a CDATA section.
- *
- * @exception SAXException If this method was not called appropriately.
+ * Constructs a new instance that appends nodes to the given parent node.<br/>
+ * Note : you cannot use a <code>Listener<code> when appending to a
+ * <code>Node</code>, because the notification occurs at
<code>endDocument()</code>
+ * which does not happen here.
*/
- public void endCDATA()
- throws SAXException {
- // This method can only called at BODY level
- if(state!=S_CDATA) throw new SAXException("Invalid state"+location());
- // Set the parent of the CDATASection as the current element
- // We don't need to check the node type because in CDATA state the
- // current element can be ONLY a CDATASection node
- this.current=this.current.getParentNode();
- if (this.current==null) throw new SAXException("No parent"+location());
- // Do a state change, and revert to the BODY state
- state=S_BODY;
+ public DOMBuilder( Node parentNode ) {
+ this(null, null, parentNode);
}
/**
- * Report the beginning of an entity.
- *
- * @param chars The characters from the XML document.
- * @param start The start position in the array.
- * @param len The number of characters to read from the array.
- * @exception SAXException If this method was not called appropriately.
+ * Recycling
*/
- public void startEntity(java.lang.String name)
- throws SAXException {
- // This method can only called at BODY level
- if((state!=S_BODY)&&(state!=S_DTD))
- throw new SAXException("Invalid state"+location());
- // Update the current element with the entity reference node
- EntityReference eref=this.document.createEntityReference(name);
- this.current.appendChild(eref);
- this.current=eref;
+ public void recycle() {
+ super.recycle();
+ this.result = null;
}
/**
- * Report the end of an entity.
- *
- * @param chars The characters from the XML document.
- * @param start The start position in the array.
- * @param len The number of characters to read from the array.
- * @exception SAXException If this method was not called appropriately.
+ * Return the newly built Document.
*/
- public void endEntity(java.lang.String name)
- throws SAXException {
- // This method can only called at BODY level
- if(state!=S_BODY) throw new SAXException("Invalid state"+location());
-
- // Check if the current node is an entity reference
- if (this.current.getNodeType()!=Node.ENTITY_REFERENCE_NODE)
- throw new SAXException("Current node is not an entity reference"+
- location());
- // Check if the current element has the same tag name of this event
- String oldname=((EntityReference)this.current).getNodeName();
- if (!oldname.equals(name))
- throw new SAXException("Entity reference closing name '"+name+"' "+
- "differs from start name '"+oldname+"'"+
- location());
- // Restore the old node as current
- this.current=this.current.getParentNode();
- if (this.current==null) throw new SAXException("No parent"+location());
- }
-
- /**
- * Receive notification of character data.
- *
- * @param chars The characters from the XML document.
- * @param start The start position in the array.
- * @param len The number of characters to read from the array.
- * @exception SAXException If this method was not called appropriately.
- */
- public void characters (char chars[], int start, int len)
- throws SAXException {
- // This method can only called at BODY or CDATA levels
- if(state<S_BODY) throw new SAXException("Invalid state "+location());
- // Check if we are in the CDATA state
- String data=new String(chars,start,len);
- if(state==S_CDATA) {
- ((CDATASection)this.current).appendData(data);
+ public Document getDocument() {
+ if (this.result.getNode().getNodeType() == Node.DOCUMENT_NODE) {
+ return ( (Document)this.result.getNode() );
} else {
- Text text=this.document.createTextNode(data);
- this.current.appendChild(text);
+ return ( this.result.getNode().getOwnerDocument() );
}
}
/**
- * Receive notification of ignorable whitespace data.
- *
- * @param chars The characters from the XML document.
- * @param start The start position in the array.
- * @param len The number of characters to read from the array.
- * @exception SAXException If this method was not called appropriately.
- */
- public void ignorableWhitespace (char chars[], int start, int len)
- throws SAXException {
- // This is because some parsers may report ignorable whitespace outside
- // the scope of the root element
- if(state==S_DOC) return;
- // This method can only called at BODY or CDATA levels
- if(state<S_BODY) throw new SAXException("Invalid state"+location());
- // Check if we are in the CDATA state
- if(state==S_CDATA)
- throw new SAXException("CDATA sections cannot contain ignorable "+
- "whitespace"+location());
- // Create and append a text node
- Text text=this.document.createTextNode(new String(chars,start,len));
- this.current.appendChild(text);
- }
-
- /**
- * Receive notification of a processing instruction.
- *
- * @param target The processing instruction target.
- * @param data The processing instruction data.
- * @exception SAXException If this method was not called appropriately.
- */
- public void processingInstruction (String target, String data)
- throws SAXException {
- // This is because Xerces reports processing instructions inside DTDs
- if(state==S_DTD) return;
- // This method can only called at DOCUMENT or BODY levels
- if((state<S_DOC)||(state>S_BODY))
- throw new SAXException("Invalid state"+location());
- // Create and append a processing instruction node
- ProcessingInstruction pi;
- pi=this.document.createProcessingInstruction(target,data);
- this.current.appendChild(pi);
- }
-
- /**
- * Report an XML comment anywhere in the document.
+ * Receive notification of the beginning of a document.
*
- * @param chars The characters from the XML document.
- * @param start The start position in the array.
- * @param len The number of characters to read from the array.
* @exception SAXException If this method was not called appropriately.
*/
- public void comment(char chars[], int start, int len)
+ public void endDocument()
throws SAXException {
- // This is because Xerces reports comments inside DTDs
- if(state==S_DTD) return;
- // This method can only called at DOCUMENT or BODY levels
- if((state<S_DOC)||(state>S_BODY))
- throw new SAXException("Invalid state"+location());
- // Create and append a comment node
- Comment com=this.document.createComment(new String(chars,start,len));
- this.current.appendChild(com);
- }
+ super.endDocument();
- /**
- * Receive notification of a skipped entity.
- *
- * @param name The name of the skipped entity. If it is a parameter entity,
- * the name will begin with '%'.
- */
- public void skippedEntity(java.lang.String name)
- throws SAXException {
- // This method can only called at BODY level
- if(state!=S_BODY) throw new SAXException("Invalid state"+location());
- // Create and append a comment node
- EntityReference eref=this.document.createEntityReference(name);
- this.current.appendChild(eref);
+ // Notify the listener
+ this.notifyListener();
}
/**
* Receive notification of a successfully completed DOM tree generation.
*/
- protected void notify(Document doc)
+ protected void notifyListener()
throws SAXException {
- if (this.listener!=null) this.listener.notify(this.document);
- }
-
- /** Create a location string */
- private String location() {
- if (this.locator==null) return("");
- String pub=this.locator.getPublicId();
- String sys=this.locator.getSystemId();
- pub = ( ( pub == null ) ? "" : new StringBuffer( "Public ID=\"" ).append(
pub ).append( "\" " ).toString() );
- sys = ( ( sys == null ) ? "" : new StringBuffer( "System ID=\"" ).append(
sys ).append( "\" " ).toString() );
- int l = this.locator.getLineNumber();
- int c = this.locator.getColumnNumber();
- String lin = ( ( l < 0 ) ? "" : new StringBuffer( "line=" ).append( l
).append( "" ).toString() );
- String col = ( ( c < 0 ) ? "" : new StringBuffer( " col=" ).append( c
).append( "" ).toString() );
- return new StringBuffer( " (" ).append( sys ).append( pub )
- .append( lin ).append( col ).append( " State: " )
- .append( stateName[this.state] + ")" ).toString();
+ if ( this.listener != null ) this.listener.notify( this.getDocument() );
}
/**
----------------------------------------------------------------------
In case of troubles, e-mail: [EMAIL PROTECTED]
To unsubscribe, e-mail: [EMAIL PROTECTED]
For additional commands, e-mail: [EMAIL PROTECTED]