Bug 33868 - [PATCH] Xslt task should support "<?xml-stylesheet ... ?>"
Summary: [PATCH] Xslt task should support "<?xml-stylesheet ... ?>"
Status: NEW
Alias: None
Product: Ant
Classification: Unclassified
Component: Core tasks (show other bugs)
Version: unspecified
Hardware: All All
: P2 enhancement (vote)
Target Milestone: ---
Assignee: Ant Notifications List
URL:
Keywords: PatchAvailable
Depends on:
Blocks:
 
Reported: 2005-03-06 10:50 UTC by Gerd Mathar
Modified: 2009-07-31 05:58 UTC (History)
0 users



Attachments
The correct patch without the additional line breaks (9.71 KB, patch)
2005-03-09 10:18 UTC, Gerd Mathar
Details | Diff

Note You need to log in before you can comment on or make changes to this bug.
Description Gerd Mathar 2005-03-06 10:50:26 UTC
Problem:
The Xslt core task has a required "style" attribute which specifies a single
stylesheet to be used for transforming, even if multiple xml source files are
processed in one task run. IMHO this is a major flexibility drawback and not a
good thing :)

Solution:
The TraX API knows about the "xml-stylesheet" processing instruction. This
instruction in an xml source file tells the XSLT processor which stylesheet to
use for transforming this particular xml file. The Xslt task should support
this, so if no style attribute is given, it would try to use the stylesheet(s)
specified by processing instruction in the xml source file(s).

Implementation:
The following patch implements the solution mentioned above. It was generated
against todays HEAD revision and affects three files:
/ant/src/main/org/apache/tools/ant/taskdefs/XSLTLiaison2.java
/ant/src/main/org/apache/tools/ant/taskdefs/XSLTProcess.java
/ant/src/main/org/apache/tools/ant/taskdefs/optional/TraXLiaison.java

Limitations:
- The W3C recommendation defining the "xml-stylesheet" processing instruction
allows any number of them to show up in an xml file. The active one is selected
by several optional pseudo-attributes of the processing instructions on each
trasformation run. The patch doesnt support this, but it wouldnt be hard to do.
- Works for TraX processors only. Forget about the others anyway... :)
- The reloadstylesheet attribute of the Xslt task is implicitly set true if the
xml-stylesheet proc. inst. are used.

---------------------------------- snip -------------------------------------

Index: src/main/org/apache/tools/ant/taskdefs/XSLTLiaison2.java
===================================================================
RCS file:
/home/cvspublic/ant/src/main/org/apache/tools/ant/taskdefs/XSLTLiaison2.java,v
retrieving revision 1.7
diff -u -r1.7 XSLTLiaison2.java
--- src/main/org/apache/tools/ant/taskdefs/XSLTLiaison2.java	9 Mar 2004
16:48:07 -0000	1.7
+++ src/main/org/apache/tools/ant/taskdefs/XSLTLiaison2.java	6 Mar 2005 08:39:25
-0000
@@ -17,6 +17,9 @@
 
 package org.apache.tools.ant.taskdefs;
 
+import java.io.File;
+import org.apache.tools.ant.BuildException;
+
 /**
  * Extended Proxy interface for XSLT processors.
  *
@@ -28,4 +31,9 @@
      * Configure the liasion from the XSLTProcess task
      */
     void configure(XSLTProcess xsltTask);
+    
+    /**
+     * Get the stylesheet for an xml source file
+     */
+    File getStylesheet(File xmlFile) throws BuildException;
 }
Index: src/main/org/apache/tools/ant/taskdefs/XSLTProcess.java
===================================================================
RCS file:
/home/cvspublic/ant/src/main/org/apache/tools/ant/taskdefs/XSLTProcess.java,v
retrieving revision 1.90
diff -u -r1.90 XSLTProcess.java
--- src/main/org/apache/tools/ant/taskdefs/XSLTProcess.java	6 Jan 2005
12:05:05 -0000	1.90
+++ src/main/org/apache/tools/ant/taskdefs/XSLTProcess.java	6 Mar 2005 08:39:28
-0000
@@ -36,7 +36,7 @@
  * Processes a set of XML documents via XSLT. This is
  * useful for building views of XML based documentation.
  *
- * @version $Revision: 1.90 $
+ * @version $Revision: 1.78.2.7 $
  *
  * @since Ant 1.1
  *
@@ -197,10 +197,6 @@
         String[]         list;
         String[]         dirs;
 
-        if (xslFile == null) {
-            throw new BuildException("no stylesheet specified", getLocation());
-        }
-
         if (inFile != null && !inFile.exists()) {
             throw new BuildException("input file " + inFile.toString() + " does
not exist", getLocation());
         }
@@ -219,17 +215,35 @@
 
             log("Using " + liaison.getClass().toString(), Project.MSG_VERBOSE);
 
-            File stylesheet = getProject().resolveFile(xslFile);
-            if (!stylesheet.exists()) {
-                stylesheet = FILE_UTILS.resolveFile(baseDir, xslFile);
-                /*
-                 * shouldn't throw out deprecation warnings before we know,
-                 * the wrong version has been used.
-                 */
-                if (stylesheet.exists()) {
-                    log("DEPRECATED - the style attribute should be relative "
-                        + "to the project\'s");
-                    log("             basedir, not the tasks\'s basedir.");
+            /* if no style attribute is given, the stylesheet will be
+             * determined by the "xml-stylesheet" processing directive
+             * of every single xml file
+             */
+            File stylesheet = null;
+            if (xslFile == null) {
+                if (!(liaison instanceof XSLTLiaison2)) {
+                    throw new BuildException(
+                        "attribute \"style\" is required if \"processor\" is
not \"trax\"",
+                        getLocation());
+                }
+                log("Using \"xml-stylesheet\" processing directive(s), " +
+                    " the reloadstylesheet attribute is set to \"true\"", +
+                    Project.MSG_INFO);
+                this.reuseLoadedStylesheet = false;
+            }
+            else {
+                stylesheet = getProject().resolveFile(xslFile);
+                if (!stylesheet.exists()) {
+                    stylesheet = FILE_UTILS.resolveFile(baseDir, xslFile);
+                    /*
+                     * shouldn't throw out deprecation warnings before we know,
+                     * the wrong version has been used.
+                     */
+                    if (stylesheet.exists()) {
+                        log("DEPRECATED - the style attribute should be relative "
+                            + "to the project\'s");
+                        log("             basedir, not the tasks\'s basedir.");
+                    }
                 }
             }
 
@@ -464,7 +478,6 @@
         File   inF = null;
 
         try {
-            long styleSheetLastModified = stylesheet.lastModified();
             inF = new File(baseDir, xmlFile);
 
             if (inF.isDirectory()) {
@@ -493,15 +506,7 @@
 
             outF = new File(destDir, outFileName[0]);
 
-            if (force
-                || inF.lastModified() > outF.lastModified()
-                || styleSheetLastModified > outF.lastModified()) {
-                ensureDirectoryFor(outF);
-                log("Processing " + inF + " to " + outF);
-
-                configureLiaison(stylesheet);
-                liaison.transform(inF, outF);
-            }
+            update(inF, outF, stylesheet);
         } catch (Exception ex) {
             // If failed to process document, must delete target document,
             // or it will not attempt to process it the second time
@@ -526,25 +531,11 @@
     private void process(File inFile, File outFile, File stylesheet)
          throws BuildException {
         try {
-            long styleSheetLastModified = stylesheet.lastModified();
             log("In file " + inFile + " time: " + inFile.lastModified(),
                 Project.MSG_DEBUG);
             log("Out file " + outFile + " time: " + outFile.lastModified(),
                 Project.MSG_DEBUG);
-            log("Style file " + xslFile + " time: " + styleSheetLastModified,
-                Project.MSG_DEBUG);
-            if (force || inFile.lastModified() >= outFile.lastModified()
-                || styleSheetLastModified >= outFile.lastModified()) {
-                ensureDirectoryFor(outFile);
-                log("Processing " + inFile + " to " + outFile,
-                    Project.MSG_INFO);
-                configureLiaison(stylesheet);
-                liaison.transform(inFile, outFile);
-            } else {
-                log("Skipping input file " + inFile
-                    + " because it is older than output file " + outFile
-                    + " and so is the stylesheet " + stylesheet,
Project.MSG_DEBUG);
-            }
+            update(inFile, outFile, stylesheet);
         } catch (Exception ex) {
             log("Failed to process " + inFile, Project.MSG_INFO);
             if (outFile != null) {
@@ -555,6 +546,38 @@
     }
 
     /**
+     * Configure and call the liaison transformation
+     * 
+     * @param inFile the input file to process.
+     * @param outFile the destination file.
+     * @param stylesheet the stylesheet to use.
+     */
+    private void update(File inFile, File outFile, File stylesheet)
+            throws BuildException, Exception {
+        File xslFile;
+        if (stylesheet == null) {
+            xslFile = ((XSLTLiaison2)liaison).getStylesheet(inFile);
+        }
+        else {
+            xslFile = stylesheet;
+        }
+        log("Style file " + xslFile + " time: " + xslFile.lastModified(),
+            Project.MSG_DEBUG);
+        if (force || inFile.lastModified() >= outFile.lastModified()
+                || xslFile.lastModified() >= outFile.lastModified()) {
+            ensureDirectoryFor(outFile);
+            log("Processing " + inFile + " to " + outFile, Project.MSG_INFO);
+            configureLiaison(xslFile);
+            liaison.transform(inFile, outFile);
+        } else {
+            log("Skipping input file " + inFile
+                + " because it is older than output file " + outFile
+                + " and so is the stylesheet " + stylesheet,
+                Project.MSG_DEBUG);
+        }
+    }
+
+    /**
      * Ensure the directory exists for a given file
      *
      * @param targetFile the file for which the directories are required.
Index: src/main/org/apache/tools/ant/taskdefs/optional/TraXLiaison.java
===================================================================
RCS file:
/home/cvspublic/ant/src/main/org/apache/tools/ant/taskdefs/optional/TraXLiaison.java,v
retrieving revision 1.35
diff -u -r1.35 TraXLiaison.java
--- src/main/org/apache/tools/ant/taskdefs/optional/TraXLiaison.java	9 Mar 2004
16:48:15 -0000	1.35
+++ src/main/org/apache/tools/ant/taskdefs/optional/TraXLiaison.java	6 Mar 2005
08:39:30 -0000
@@ -25,6 +25,7 @@
 import java.io.IOException;
 import java.io.InputStream;
 import java.io.OutputStream;
+import java.net.URI;
 import java.util.Vector;
 import java.util.Enumeration;
 import javax.xml.parsers.ParserConfigurationException;
@@ -430,4 +431,32 @@
             setOutputProperty(prop.getName(), prop.getValue());
         }
     }
+    
+    /**
+     * Get the stylesheet for an xml source file from its "xml-stylesheet"
+     * processing instruction
+     * 
+     * @param xmlFile the xml source file in question
+     * @return the stylesheet file
+     */
+    public File getStylesheet(File xmlFile)
+            throws BuildException {
+        File xslFile = null;
+        Source xmlSource = new StreamSource(xmlFile);
+        Source xslSource;
+        
+        try {
+            xslSource = getFactory().getAssociatedStylesheet(
+                xmlSource, null, null, null);
+            if (xslSource == null) {
+                throw new TransformerConfigurationException(
+                    "no matching \"xml-stylesheet\" processing instruction");
+            }
+            xslFile = new File((new URI(xslSource.getSystemId())).getPath());
+        }
+        catch (Exception e) {
+            throw new BuildException(e);
+        }
+        return xslFile;
+    }
 }
Comment 1 Gerd Mathar 2005-03-09 10:18:39 UTC
Created attachment 14438 [details]
The correct patch without the additional line breaks
Comment 2 Gerd Mathar 2005-03-09 10:22:41 UTC
(In reply to comment #0)
The patch included in the original report is broken because of additional line
breaks, sry :o/. I attached the correct one to it.