cocoon-cvs mailing list archives

Site index · List index
Message view « Date » · « Thread »
Top « Date » · « Thread »
From reinh...@apache.org
Subject svn commit: r882881 - in /cocoon/cocoon3/trunk/cocoon-sax: ./ src/main/java/org/apache/cocoon/sax/component/ src/main/java/org/apache/cocoon/sax/util/ src/test/java/org/apache/cocoon/sax/ src/test/resources/META-INF/ src/test/resources/META-INF/services/
Date Sat, 21 Nov 2009 10:55:40 GMT
Author: reinhard
Date: Sat Nov 21 10:55:38 2009
New Revision: 882881

URL: http://svn.apache.org/viewvc?rev=882881&view=rev
Log:
COCOON3-6 Enhance the reusability of the XSLTTransformer and support Xalan's XSLTC engine.
Thanks Simone

Added:
    cocoon/cocoon3/trunk/cocoon-sax/src/test/resources/META-INF/
    cocoon/cocoon3/trunk/cocoon-sax/src/test/resources/META-INF/services/
    cocoon/cocoon3/trunk/cocoon-sax/src/test/resources/META-INF/services/javax.xml.transform.TransformerFactory
Removed:
    cocoon/cocoon3/trunk/cocoon-sax/src/main/java/org/apache/cocoon/sax/component/XSLTProcessorErrorListener.java
Modified:
    cocoon/cocoon3/trunk/cocoon-sax/pom.xml
    cocoon/cocoon3/trunk/cocoon-sax/src/main/java/org/apache/cocoon/sax/component/XSLTTransformer.java
    cocoon/cocoon3/trunk/cocoon-sax/src/main/java/org/apache/cocoon/sax/util/TransformationUtils.java
    cocoon/cocoon3/trunk/cocoon-sax/src/test/java/org/apache/cocoon/sax/PipelineTest.java

Modified: cocoon/cocoon3/trunk/cocoon-sax/pom.xml
URL: http://svn.apache.org/viewvc/cocoon/cocoon3/trunk/cocoon-sax/pom.xml?rev=882881&r1=882880&r2=882881&view=diff
==============================================================================
--- cocoon/cocoon3/trunk/cocoon-sax/pom.xml (original)
+++ cocoon/cocoon3/trunk/cocoon-sax/pom.xml Sat Nov 21 10:55:38 2009
@@ -70,6 +70,78 @@
       <groupId>xmlunit</groupId>
       <artifactId>xmlunit</artifactId>
       <scope>test</scope>
-    </dependency>    
+    </dependency>
+    <dependency>
+      <groupId>xalan</groupId>
+      <artifactId>xalan</artifactId>
+      <version>2.7.1</version>
+      <scope>test</scope>
+      <exclusions>
+        <exclusion>
+          <groupId>xml-apis</groupId>
+          <artifactId>xml-apis</artifactId>
+        </exclusion>
+      </exclusions>
+    </dependency>
   </dependencies>
+
+  <build>
+    <plugins>
+      <plugin>
+        <groupId>org.codehaus.mojo</groupId>
+        <artifactId>exec-maven-plugin</artifactId>
+        <executions>
+          <execution>
+            <phase>test-compile</phase>
+            <goals>
+              <goal>exec</goal>
+            </goals>
+          </execution>
+        </executions>
+        <configuration>
+          <executable>java</executable>
+          <classpathScope>test</classpathScope>
+          <arguments>
+            <argument>-classpath</argument>
+            <classpath/>
+            <argument>org.apache.xalan.xsltc.cmdline.Compile</argument>
+            <argument>-d</argument>
+            <argument>target/test-classes</argument>
+            <argument>-p</argument>
+            <argument>org.apache.cocoon.sax</argument>
+            <argument>-o</argument>
+            <argument>CompiledXslt</argument>
+            <argument>src/test/resources/test.xslt</argument>
+          </arguments>
+        </configuration>
+      </plugin>
+    </plugins>
+  </build>
+  
+  <profiles>
+    <profile>
+      <id>it</id>
+      <build>
+        <plugins>
+          <plugin>
+            <groupId>org.codehaus.mojo</groupId>
+            <artifactId>rat-maven-plugin</artifactId>
+            <configuration>
+              <excludes>
+                <exclude>src/test/resources/META-INF/services/javax.xml.transform.TransformerFactory</exclude>
+              </excludes>
+            </configuration>            
+            <executions>
+              <execution>
+                <phase>verify</phase>
+                <goals>
+                  <goal>check</goal>
+                </goals>
+              </execution>
+            </executions>
+          </plugin>          
+        </plugins>
+      </build>        
+    </profile>  
+  </profiles>   
 </project>

Modified: cocoon/cocoon3/trunk/cocoon-sax/src/main/java/org/apache/cocoon/sax/component/XSLTTransformer.java
URL: http://svn.apache.org/viewvc/cocoon/cocoon3/trunk/cocoon-sax/src/main/java/org/apache/cocoon/sax/component/XSLTTransformer.java?rev=882881&r1=882880&r2=882881&view=diff
==============================================================================
--- cocoon/cocoon3/trunk/cocoon-sax/src/main/java/org/apache/cocoon/sax/component/XSLTTransformer.java
(original)
+++ cocoon/cocoon3/trunk/cocoon-sax/src/main/java/org/apache/cocoon/sax/component/XSLTTransformer.java
Sat Nov 21 10:55:38 2009
@@ -20,13 +20,17 @@
 import java.util.HashMap;
 import java.util.Map;
 import java.util.Map.Entry;
+import java.util.regex.Pattern;
 
+import javax.xml.transform.Source;
+import javax.xml.transform.Templates;
 import javax.xml.transform.Transformer;
+import javax.xml.transform.TransformerConfigurationException;
 import javax.xml.transform.TransformerFactory;
 import javax.xml.transform.sax.SAXResult;
 import javax.xml.transform.sax.SAXTransformerFactory;
-import javax.xml.transform.sax.TemplatesHandler;
 import javax.xml.transform.sax.TransformerHandler;
+import javax.xml.transform.stream.StreamSource;
 
 import org.apache.cocoon.pipeline.SetupException;
 import org.apache.cocoon.pipeline.util.StringRepresentation;
@@ -35,63 +39,173 @@
 import org.apache.cocoon.sax.util.SAXConsumerAdapter;
 import org.apache.commons.logging.Log;
 import org.apache.commons.logging.LogFactory;
-import org.xml.sax.InputSource;
-import org.xml.sax.XMLReader;
-import org.xml.sax.helpers.XMLReaderFactory;
 
 public class XSLTTransformer extends AbstractSAXTransformer {
 
+    /**
+     * A generic transformer factory to parse XSLTs.
+     */
+    private static final SAXTransformerFactory TRAX_FACTORY = createNewSAXTransformerFactory();
+
+    /**
+     * The XSLT parameters name pattern.
+     */
+    private static final Pattern XSLT_PARAMETER_NAME_PATTERN = Pattern.compile("[a-zA-Z_][\\w\\-\\.]*");
+
+    /**
+     * This class log.
+     */
     private final Log log = LogFactory.getLog(XSLTTransformer.class);
+
+    /**
+     * The XSLT parameters reference.
+     */
     private Map<String, Object> parameters;
+
+    /**
+     * The XSLT URL source.
+     */
     private URL source;
 
+    /**
+     * The XSLT Template reference.
+     */
+    private Templates templates;
+
+    /**
+     * Empty constructor, used in sitemap.
+     */
     public XSLTTransformer() {
         super();
     }
 
-    public XSLTTransformer(URL source) {
+    /**
+     * Creates a new transformer reading the XSLT from the URL source.
+     *
+     * @param source the XSLT URL source
+     */
+    public XSLTTransformer(final URL source) {
         this(source, null);
     }
 
-    public XSLTTransformer(URL source, Map<String, Object> parameters) {
+    /**
+     * Creates a new transformer reading the XSLT from the URL source and setting the Transformer
+     * Factory attributes.
+     *
+     * This constructor is useful when users want to perform XSLT transformation using <a
+     * href="http://xml.apache.org/xalan-j/xsltc_usage.html">xsltc</a>.
+     *
+     * @param source the XSLT URL source
+     * @param attributes the Transformer Factory attributes
+     */
+    public XSLTTransformer(final URL source, final Map<String, Object> attributes)
{
         super();
+        this.loadXSLT(source, attributes);
+    }
+
+    /**
+     * Method useful to create a new transformer reading the XSLT from the URL source and
setting
+     * the Transformer Factory attributes.
+     *
+     * This method is useful when users want to perform XSLT transformation using <a
+     * href="http://xml.apache.org/xalan-j/xsltc_usage.html">xsltc</a>.
+     *
+     * @param source the XSLT URL source
+     * @param attributes the Transformer Factory attributes
+     */
+    private void loadXSLT(final URL source, final Map<String, Object> attributes) {
         if (source == null) {
             throw new IllegalArgumentException("The parameter 'source' mustn't be null.");
         }
 
-        this.parameters = parameters;
         this.source = source;
+
+        Source urlSource = new StreamSource(this.source.toExternalForm());
+
+        SAXTransformerFactory transformerFactory;
+        if (attributes != null && !attributes.isEmpty()) {
+            transformerFactory = createNewSAXTransformerFactory();
+            for (Entry<String, Object> attribute : attributes.entrySet()) {
+                String name = attribute.getKey();
+                Object value = attribute.getValue();
+                transformerFactory.setAttribute(name, value);
+            }
+        } else {
+            transformerFactory = TRAX_FACTORY;
+        }
+
+        try {
+            this.templates = transformerFactory.newTemplates(urlSource);
+        } catch (TransformerConfigurationException e) {
+            throw new SetupException("Impossible to read XSLT from '" + this.source.toExternalForm()
+                    + "', see nested exception", e);
+        }
     }
 
     /**
-     * Test if the name is a valid parameter name for XSLT
+     * Sets the XSLT parameters to be applied to XSLT stylesheet.
+     *
+     * @param parameters the XSLT parameters to be applied to XSLT stylesheet
      */
-    private static boolean isValidXSLTParameterName(String name) {
-        return name.matches("[a-zA-Z_][\\w\\-\\.]*");
+    public void setParameters(final Map<String, ? extends Object> parameters) {
+        if (parameters != null) {
+            this.parameters = new HashMap<String, Object>(parameters);
+        } else {
+            this.parameters = null;
+        }
     }
 
+    /**
+     * {@inheritDoc}
+     */
     @Override
-    public void setConfiguration(Map<String, ? extends Object> configuration) {
-        this.source = (URL) configuration.get("source");
+    @SuppressWarnings("unchecked")
+    public void setConfiguration(final Map<String, ? extends Object> configuration)
{
+        try {
+            this.source = (URL) configuration.get("source");
+        } catch (ClassCastException cce) {
+            throw new SetupException("The configuration value of 'source' can't be cast to
java.net.URL.", cce);
+        }
 
-        this.parameters = new HashMap<String, Object>(configuration);
+        if (this.source != null) {
+            Object attributesObj = configuration.get("attributes");
+            if (attributesObj != null && attributesObj instanceof Map) {
+                this.loadXSLT(this.source, (Map) attributesObj);
+            } else {
+                this.loadXSLT(this.source, null);
+            }
+        } else {
+            if (this.log.isDebugEnabled()) {
+                this.log.debug("Impossible to load XSLT parameters from '" + this.source
+                        + "' source, make sure it is NOT null and is a valid URL");
+            }
+        }
+
+        this.setParameters(configuration);
     }
 
+    /**
+     * {@inheritDoc}
+     */
     @Override
-    protected void setSAXConsumer(SAXConsumer consumer) {
+    protected void setSAXConsumer(final SAXConsumer consumer) {
         TransformerHandler transformerHandler;
         try {
-            transformerHandler = this.createTransformerHandler();
+            transformerHandler = TRAX_FACTORY.newTransformerHandler(this.templates);
         } catch (Exception ex) {
             throw new SetupException("Could not initialize transformer handler.", ex);
         }
 
-        final Map<String, Object> map = this.getLogicSheetParameters();
-        if (map != null) {
+        if (this.parameters != null) {
             final Transformer transformer = transformerHandler.getTransformer();
 
-            for (Entry<String, Object> entry : map.entrySet()) {
-                transformer.setParameter(entry.getKey(), entry.getValue());
+            for (Entry<String, Object> entry : this.parameters.entrySet()) {
+                String name = entry.getKey();
+
+                // is valid XSLT parameter name
+                if (XSLT_PARAMETER_NAME_PATTERN.matcher(name).matches()) {
+                    transformer.setParameter(name, entry.getValue());
+                }
             }
         }
 
@@ -109,40 +223,13 @@
         super.setSAXConsumer(saxConsumerAdapter);
     }
 
-    private TransformerHandler createTransformerHandler() throws Exception {
-        SAXTransformerFactory transformerFactory = (SAXTransformerFactory) TransformerFactory.newInstance();
-        TemplatesHandler templatesHandler = transformerFactory.newTemplatesHandler();
-
-        XMLReader xmlReader = XMLReaderFactory.createXMLReader();
-        xmlReader.setContentHandler(templatesHandler);
-        String systemId = this.source.toURI().toString();
-        InputSource inputSource = new InputSource(systemId);
-        xmlReader.parse(inputSource);
-
-        // Create transformer handler
-        final TransformerHandler handler = transformerFactory.newTransformerHandler(templatesHandler.getTemplates());
-        handler.getTransformer().setErrorListener(
-                new XSLTProcessorErrorListener(this.log, this.source.toExternalForm()));
-
-        return handler;
-    }
-
-    private Map<String, Object> getLogicSheetParameters() {
-        if (this.parameters == null) {
-            return null;
-        }
-
-        Map<String, Object> result = new HashMap<String, Object>();
-
-        for (Entry<String, Object> entry : this.parameters.entrySet()) {
-            String name = entry.getKey();
-
-            if (isValidXSLTParameterName(name)) {
-                result.put(name, entry.getValue());
-            }
-        }
-
-        return result;
+    /**
+     * Utility method to create a new transformer factory.
+     *
+     * @return a new transformer factory
+     */
+    private static SAXTransformerFactory createNewSAXTransformerFactory() {
+        return (SAXTransformerFactory) TransformerFactory.newInstance();
     }
 
     @Override

Modified: cocoon/cocoon3/trunk/cocoon-sax/src/main/java/org/apache/cocoon/sax/util/TransformationUtils.java
URL: http://svn.apache.org/viewvc/cocoon/cocoon3/trunk/cocoon-sax/src/main/java/org/apache/cocoon/sax/util/TransformationUtils.java?rev=882881&r1=882880&r2=882881&view=diff
==============================================================================
--- cocoon/cocoon3/trunk/cocoon-sax/src/main/java/org/apache/cocoon/sax/util/TransformationUtils.java
(original)
+++ cocoon/cocoon3/trunk/cocoon-sax/src/main/java/org/apache/cocoon/sax/util/TransformationUtils.java
Sat Nov 21 10:55:38 2009
@@ -164,7 +164,9 @@
 
         pipeline.addComponent(new StringGenerator(xmlString));
         for (URL xsltUrl : xsltUrls) {
-            pipeline.addComponent(new XSLTTransformer(xsltUrl, xsltParameters));
+            XSLTTransformer xsltTransformer = new XSLTTransformer(xsltUrl);
+            xsltTransformer.setParameters(xsltParameters);
+            pipeline.addComponent(xsltTransformer);
         }
         pipeline.addComponent(new XMLSerializer(outputProperties));
 

Modified: cocoon/cocoon3/trunk/cocoon-sax/src/test/java/org/apache/cocoon/sax/PipelineTest.java
URL: http://svn.apache.org/viewvc/cocoon/cocoon3/trunk/cocoon-sax/src/test/java/org/apache/cocoon/sax/PipelineTest.java?rev=882881&r1=882880&r2=882881&view=diff
==============================================================================
--- cocoon/cocoon3/trunk/cocoon-sax/src/test/java/org/apache/cocoon/sax/PipelineTest.java
(original)
+++ cocoon/cocoon3/trunk/cocoon-sax/src/test/java/org/apache/cocoon/sax/PipelineTest.java
Sat Nov 21 10:55:38 2009
@@ -19,6 +19,8 @@
 package org.apache.cocoon.sax;
 
 import java.io.ByteArrayOutputStream;
+import java.util.HashMap;
+import java.util.Map;
 
 import junit.framework.TestCase;
 
@@ -33,7 +35,7 @@
 
     /**
      * A pipeline that performs a simple transformation: generator -&gt; transformer
-&gt;
-     * serializer
+     * serializer.
      */
     public void testPipelineWithTransformer() throws Exception {
         Pipeline<SAXPipelineComponent> pipeline = new NonCachingPipeline<SAXPipelineComponent>();
@@ -48,4 +50,28 @@
         Diff diff = new Diff("<?xml version=\"1.0\" encoding=\"UTF-8\"?><p></p>",
new String(baos.toByteArray()));
         assertTrue("XSL transformation didn't work as expected " + diff, diff.identical());
     }
+
+    /**
+     * A pipeline that performs a simple transformation: generator -&gt; transformer
-&gt;
+     * serializer; the transformer uses a compiled XSLT using Xalan xsltc.
+     * 
+     * @throws Exception if any error occurs.
+     */
+    public void testPipelineWithCompiledXSLT() throws Exception {
+        Map<String, Object> attributes = new HashMap<String, Object>();
+        attributes.put("translet-name", "CompiledXslt");
+        attributes.put("package-name", "org.apache.cocoon.sax");
+
+        Pipeline<SAXPipelineComponent> pipeline = new NonCachingPipeline<SAXPipelineComponent>();
+        pipeline.addComponent(new StringGenerator("<x></x>"));
+        pipeline.addComponent(new XSLTTransformer(this.getClass().getResource("/test.xslt"),
attributes));
+        pipeline.addComponent(new XMLSerializer());
+
+        ByteArrayOutputStream baos = new ByteArrayOutputStream();
+        pipeline.setup(baos);
+        pipeline.execute();
+
+        Diff diff = new Diff("<?xml version=\"1.0\" encoding=\"UTF-8\"?><p></p>",
new String(baos.toByteArray()));
+        assertTrue("XSL transformation didn't work as expected " + diff, diff.identical());
+    }
 }

Added: cocoon/cocoon3/trunk/cocoon-sax/src/test/resources/META-INF/services/javax.xml.transform.TransformerFactory
URL: http://svn.apache.org/viewvc/cocoon/cocoon3/trunk/cocoon-sax/src/test/resources/META-INF/services/javax.xml.transform.TransformerFactory?rev=882881&view=auto
==============================================================================
--- cocoon/cocoon3/trunk/cocoon-sax/src/test/resources/META-INF/services/javax.xml.transform.TransformerFactory
(added)
+++ cocoon/cocoon3/trunk/cocoon-sax/src/test/resources/META-INF/services/javax.xml.transform.TransformerFactory
Sat Nov 21 10:55:38 2009
@@ -0,0 +1 @@
+org.apache.xalan.xsltc.trax.TransformerFactoryImpl



Mime
View raw message