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]