You are viewing a plain text version of this content. The canonical link for it is here.
Posted to cvs@cocoon.apache.org by vg...@apache.org on 2005/04/22 02:26:12 UTC
svn commit: r164154 -
/cocoon/trunk/src/java/org/apache/cocoon/transformation/AbstractSAXTransformer.java
Author: vgritsenko
Date: Thu Apr 21 17:26:11 2005
New Revision: 164154
URL: http://svn.apache.org/viewcvs?rev=164154&view=rev
Log:
Add transformer-factory configuration.
Add support for capturing XMLizable.
Use XMLizable for serialized XML recording - no need for DOM!
Modified:
cocoon/trunk/src/java/org/apache/cocoon/transformation/AbstractSAXTransformer.java
Modified: cocoon/trunk/src/java/org/apache/cocoon/transformation/AbstractSAXTransformer.java
URL: http://svn.apache.org/viewcvs/cocoon/trunk/src/java/org/apache/cocoon/transformation/AbstractSAXTransformer.java?rev=164154&r1=164153&r2=164154&view=diff
==============================================================================
--- cocoon/trunk/src/java/org/apache/cocoon/transformation/AbstractSAXTransformer.java (original)
+++ cocoon/trunk/src/java/org/apache/cocoon/transformation/AbstractSAXTransformer.java Thu Apr 21 17:26:11 2005
@@ -32,6 +32,8 @@
import org.apache.avalon.framework.service.ServiceManager;
import org.apache.avalon.framework.service.Serviceable;
import org.apache.cocoon.ProcessingException;
+import org.apache.cocoon.util.ClassUtils;
+import org.apache.cocoon.util.TraxErrorHandler;
import org.apache.cocoon.environment.Context;
import org.apache.cocoon.environment.ObjectModelHelper;
import org.apache.cocoon.environment.Request;
@@ -56,6 +58,9 @@
import org.xml.sax.ext.LexicalHandler;
import org.xml.sax.helpers.AttributesImpl;
+import javax.xml.transform.sax.SAXTransformerFactory;
+import javax.xml.transform.TransformerFactory;
+
/**
* This class is the basis for all transformers. It provides various useful
* methods and hooks for implementing own custom transformers.
@@ -103,6 +108,11 @@
implements Serviceable, Configurable, Recyclable {
/**
+ * The trax <code>TransformerFactory</code> used by this transformer.
+ */
+ private SAXTransformerFactory tfactory;
+
+ /**
* Controlls SAX event handling.
* If set to true all whitespace events are ignored.
*/
@@ -150,31 +160,56 @@
* The stack is important for collection information especially when
* the tags can be nested.
*/
- protected Stack stack = new Stack();
+ protected final Stack stack = new Stack();
/**
* The stack of current used recorders
*/
- protected Stack recorderStack = new Stack();
+ protected final Stack recorderStack = new Stack();
+
+ /**
+ * The current Request object
+ */
+ protected Request request;
- /** The current Request object */
- protected Request request;
- /** The current Response object */
- protected Response response;
- /** The current Context object */
- protected Context context;
- /** The current objectModel of the environment */
- protected Map objectModel;
- /** The parameters specified in the sitemap */
- protected Parameters parameters;
- /** The source attribute specified in the sitemap */
- protected String source;
- /** The Avalon ServiceManager for getting Components */
- protected ServiceManager manager;
- /** The SourceResolver for this request */
- protected SourceResolver resolver;
+ /**
+ * The current Response object
+ */
+ protected Response response;
+
+ /**
+ * The current Context object
+ */
+ protected Context context;
+
+ /**
+ * The current objectModel of the environment
+ */
+ protected Map objectModel;
+
+ /**
+ * The parameters specified in the sitemap
+ */
+ protected Parameters parameters;
+
+ /**
+ * The source attribute specified in the sitemap
+ */
+ protected String source;
+
+ /**
+ * The Avalon ServiceManager for getting Components
+ */
+ protected ServiceManager manager;
+
+ /**
+ * The SourceResolver for this request
+ */
+ protected SourceResolver resolver;
- /** Are we already initialized for the current request? */
+ /**
+ * Are we already initialized for the current request?
+ */
private boolean isInitialized;
/**
@@ -184,10 +219,14 @@
*/
protected AttributesImpl emptyAttributes = new AttributesImpl();
- /** The namespaces and their prefixes */
- private List namespaces = new ArrayList(5);
+ /**
+ * The namespaces and their prefixes
+ */
+ private final List namespaces = new ArrayList(5);
- /** The current prefix for our namespace */
+ /**
+ * The current prefix for our namespace
+ */
private String ourPrefix;
@@ -195,6 +234,21 @@
* @see Configurable#configure(Configuration)
*/
public void configure(Configuration configuration) throws ConfigurationException {
+ String tFactoryClass = configuration.getChild("transformer-factory").getValue(null);
+ if (tFactoryClass != null) {
+ try {
+ this.tfactory = (SAXTransformerFactory) ClassUtils.newInstance(tFactoryClass);
+ if (getLogger().isDebugEnabled()) {
+ getLogger().debug("Using transformer factory " + tFactoryClass);
+ }
+ } catch (Exception e) {
+ throw new ConfigurationException("Cannot load transformer factory " + tFactoryClass, e);
+ }
+ } else {
+ // Standard TrAX behaviour
+ this.tfactory = (SAXTransformerFactory) TransformerFactory.newInstance();
+ }
+ tfactory.setErrorListener(new TraxErrorHandler(getLogger()));
}
/* (non-Javadoc)
@@ -242,6 +296,7 @@
*/
public void recycle() {
super.recycle();
+
this.namespaceURI = null;
this.objectModel = null;
this.request = null;
@@ -273,14 +328,15 @@
throws SAXException {
if (!this.isInitialized) {
try {
- this.setupTransforming();
- } catch (ProcessingException local) {
- throw new SAXException("ProcessingException: " + local, local);
- } catch (IOException ioe) {
- throw new SAXException("IOException: " + ioe, ioe);
+ setupTransforming();
+ } catch (ProcessingException e) {
+ throw new SAXException("ProcessingException: " + e, e);
+ } catch (IOException e) {
+ throw new SAXException("IOException: " + e, e);
}
this.isInitialized = true;
}
+
if (this.ignoreEventsCount == 0) {
super.startDocument();
}
@@ -420,25 +476,26 @@
}
/**
- * Start recording of SAX events
- * All incomming events are recorded and not forwarded. The result
- * can be obtained by the matching endSAXRecording() call.
+ * Start recording of SAX events.
+ * All incoming events are recorded and not forwarded. The resulting
+ * XMLizable can be obtained by the matching {@link #endSAXRecording} call.
* @since 2.1.5
*/
public void startSAXRecording()
throws SAXException {
addRecorder(new SaxBuffer());
+ sendStartPrefixMapping();
}
/**
- * Stop DocumentFragment recording.
- * All incomming events are recorded and not forwarded. This method returns
- * the resulting DocumentFragment.
+ * Stop recording of SAX events.
+ * This method returns the resulting XMLizable.
* @since 2.1.5
*/
public XMLizable endSAXRecording()
throws SAXException {
- return (XMLizable) this.removeRecorder();
+ sendEndPrefixMapping();
+ return (XMLizable) removeRecorder();
}
/**
@@ -452,7 +509,6 @@
getLogger().debug("Start text recording");
}
addRecorder(new TextRecorder());
-
sendStartPrefixMapping();
}
@@ -485,7 +541,7 @@
getLogger().debug("Start serialized XML recording. Format=" + format);
}
this.stack.push(format == null? XMLUtils.createPropertiesForXML(false): format);
- startRecording();
+ startSAXRecording();
}
/**
@@ -495,8 +551,8 @@
*/
public String endSerializedXMLRecording()
throws SAXException, ProcessingException {
- DocumentFragment fragment = endRecording();
- String text = XMLUtils.serializeNode(fragment, (Properties) this.stack.pop());
+ XMLizable xml = endSAXRecording();
+ String text = XMLUtils.serialize(xml, (Properties) this.stack.pop());
if (getLogger().isDebugEnabled()) {
getLogger().debug("End serialized XML recording. XML=" + text);
}
@@ -516,7 +572,6 @@
getLogger().debug("Start parameters recording");
}
addRecorder(new ParametersRecorder());
-
sendStartPrefixMapping();
}
@@ -559,65 +614,70 @@
}
/**
- * Start DocumentFragment recording.
- * All incomming events are recorded and not forwarded. The resulting
- * DocumentFragment can be obtained by the matching endRecording() call.
+ * Start DOM DocumentFragment recording.
+ * All incoming events are recorded and not forwarded. The resulting
+ * DocumentFragment can be obtained by the matching {@link #endRecording} call.
*/
public void startRecording()
throws SAXException {
if (getLogger().isDebugEnabled()) {
getLogger().debug("Start recording");
}
- DOMBuilder builder = new DOMBuilder();
+ DOMBuilder builder = new DOMBuilder(this.tfactory);
addRecorder(builder);
builder.startDocument();
builder.startElement("", "cocoon", "cocoon", new AttributesImpl());
-
sendStartPrefixMapping();
}
/**
- * Stop DocumentFragment recording.
- * All incomming events are recorded and not forwarded. This method returns
- * the resulting DocumentFragment.
+ * Stop DOM DocumentFragment recording.
+ * This method returns the resulting DocumentFragment, normalized.
*/
public DocumentFragment endRecording()
throws SAXException {
sendEndPrefixMapping();
- DOMBuilder builder = (DOMBuilder)removeRecorder();
+ DOMBuilder builder = (DOMBuilder) removeRecorder();
builder.endElement("", "cocoon", "cocoon");
builder.endDocument();
// Create Document Fragment
final Document doc = builder.getDocument();
- final DocumentFragment recordedDocFrag = doc.createDocumentFragment();
+ final DocumentFragment fragment = doc.createDocumentFragment();
final Node root = doc.getDocumentElement();
+
+ // Remove empty text nodes and collapse neighbouring text nodes
root.normalize();
- boolean appendedNode = false;
- while (root.hasChildNodes() == true) {
+ // Move all nodes into the fragment
+ boolean space = true;
+ while (root.hasChildNodes()) {
Node child = root.getFirstChild();
root.removeChild(child);
- // Leave out empty text nodes before any other node
- if (appendedNode == true
- || child.getNodeType() != Node.TEXT_NODE
- || child.getNodeValue().trim().length() > 0) {
- recordedDocFrag.appendChild(child);
- appendedNode = true;
+
+ // Leave out leading whitespace nodes
+ // FIXME: Why leading spaces are trimmed at all? Why not trailing spaces?
+ if (space && child.getNodeType() == Node.TEXT_NODE
+ && child.getNodeValue().trim().length() == 0) {
+ continue;
}
+ space = false;
+
+ fragment.appendChild(child);
}
if (getLogger().isDebugEnabled()) {
Object serializedXML = null;
try {
- serializedXML = recordedDocFrag == null? "null": XMLUtils.serializeNode(recordedDocFrag);
+ serializedXML = fragment == null? "null": XMLUtils.serializeNode(fragment);
} catch (ProcessingException ignore) {
- serializedXML = recordedDocFrag;
+ serializedXML = fragment;
}
getLogger().debug("End recording. Fragment=" + serializedXML);
}
- return recordedDocFrag;
+
+ return fragment;
}
// ************
@@ -824,11 +884,10 @@
*/
protected void sendStartPrefixMapping()
throws SAXException {
-
final int l = this.namespaces.size();
- for(int i = 0; i < l; i++) {
- String[] prefixAndUri = (String[])this.namespaces.get(i);
- super.contentHandler.startPrefixMapping(prefixAndUri[0], prefixAndUri[1]);
+ for (int i = 0; i < l; i++) {
+ String[] prefixAndUri = (String[]) this.namespaces.get(i);
+ super.contentHandler.startPrefixMapping(prefixAndUri[0], prefixAndUri[1]);
}
}
@@ -837,11 +896,10 @@
*/
protected void sendEndPrefixMapping()
throws SAXException {
-
final int l = this.namespaces.size();
- for(int i=0; i<l; i++) {
- String[] prefixAndUri = (String[])this.namespaces.get(i);
- super.contentHandler.endPrefixMapping(prefixAndUri[0]);
+ for (int i = 0; i < l; i++) {
+ String[] prefixAndUri = (String[]) this.namespaces.get(i);
+ super.contentHandler.endPrefixMapping(prefixAndUri[0]);
}
}