XT extensions
1. | Where can I find out about the XT extension functions |
Looking at http://www.jclark.com/xml/xt.html, Extension Functions, A call to a function ns:foo where ns is bound to a namespace of the form http://www.jclark.com/xt/java/className is treated as a call of the static method foo of the class with fully-qualified name className." In other words, you have access to the methods of any Java class in the CLASSPATH known to the Java instance that's running XT. mkdir() is one such method that is in the standard java.io.File class. xt:mkdir has been mentioned on the list twice before, so none of you have any excuse for not having heard about xt:mkdir before now! (I'm kidding) In response, I received the following advice from James Clark on how to use what gets returned by the mkdir function in a variable:
Richard Lander gave an example. <?xml version='1.0' standalone='no'?> <!DOCTYPE xsl:stylesheet [ ]> <xsl:stylesheet xmlns:xsl="http://www.w3.org/1999/XSL/Transform" xmlns:xtfile="http://www.jclark.com/xt/java/java.io.File" version="1.0" xmlns:xt="http://www.jclark.com/xt" extension-element-prefixes="xt"> <xsl:param name="filepath" select="'Output/'"/> <xsl:output method="xml" indent="yes"/> <xsl:template match='/'> <xsl:comment> <xsl:value-of select= "xtfile:mkdir(xtfile:new(string($filepath)))"/> </xsl:comment> <xsl:apply-templates/> </xsl:template> </xsl:stylesheet> try: xt mkdir.xsl mkdir.xsl and xt mkdir.xsl mkdir.xsl filepath=anydir If you are calling xt from a batch file, you may need to use quotation marks, as in: "filepath=anydir" | |
2. | How to pipeline XT processing. |
an alternative, for xt, is to use xt:node-set. Run one set of templates and stuff the entire result tree into a variable then get it back as a node set and run some more templates on it, all within the same stylesheet. | |
3. | xt:nodeset |
An example of re-using parts of the output tree. This is a simple case, but you can get finer control if you want it. Starting from =========================================== <doc xmlns="one"> <head>test</head> <section> <head>one</head> <p>this paragraph this paragraph</p> <p>another paragraph another paragraph</p> </section> </doc> ========================================== You could use this stylesheet to get to html ========================================= <xsl:stylesheet xmlns:xsl= "http://www.w3.org/1999/XSL/Transform" version="1.0" xmlns:one="one" xmlns:two="two" > <xsl:output method="xml" indent="yes"/> <xsl:template match="one:doc"> <two:html> <two:head> <two:title><xsl:value-of select="one:head"/></two:title> </two:head> <two:body> <two:h1><xsl:value-of select="one:head"/></two:h1> <xsl:apply-templates select="one:section"/> </two:body> </two:html> </xsl:template> <xsl:template match="one:section"> <two:h2><xsl:value-of select="one:head"/></two:h2> <xsl:apply-templates select="*[not(self::one:head)]"/> </xsl:template> <xsl:template match="one:p"> <two:p><xsl:apply-templates/></two:p> </xsl:template> </xsl:stylesheet> ========================================== which results in ========================================== <?xml version="1.0" encoding="utf-8"?> <two:html xmlns:one="one" xmlns:two="two"> <two:head> <two:title>test</two:title> </two:head> <two:body> <two:h1>test</two:h1> <two:h2>one</two:h2> <two:p>this paragraph this paragraph</two:p> <two:p>another paragraph another paragraph</two:p> </two:body> </two:html> =========================================== If you had an html to text stylesheet that looked like =========================================== <xsl:stylesheet xmlns:xsl="http://www.w3.org/1999/XSL/Transform" version="1.0" xmlns:t="two" > <xsl:output method="text"/> <xsl:template match="t:head"> </xsl:template> <xsl:template match="t:h1"> <xsl:value-of select="."/> <xsl:text> </xsl:text> <xsl:value-of select="translate(.,'eston','=====')"/> <xsl:text> </xsl:text> </xsl:template> <xsl:template match="t:h2"> <xsl:value-of select="."/> <xsl:text> </xsl:text> <xsl:value-of select="translate(.,'eston','-----')"/> <xsl:text> </xsl:text> </xsl:template> <xsl:template match="t:p"> <xsl:text> </xsl:text> <xsl:apply-templates/> <xsl:text> </xsl:text> </xsl:template> </xsl:stylesheet> ========================================== You could run that on the above output and get ========================================== test ==== one - --- this paragraph this paragraph another paragraph another paragraph ========================================== Alternatively you could merge the two stylesheets and get one stylesheet that does the work of two, like this ========================================== <xsl:stylesheet xmlns:xsl= "http://www.w3.org/1999/XSL/Transform" version="1.0" xmlns:xt="http://www.jclark.com/xt" extension-element-prefixes="xt" > <xsl:output method="text"/> <xsl:import href="chain2.xsl"/> <xsl:import href="chain1.xsl"/> <xsl:template match="/"> <xsl:variable name="x"> <xsl:apply-templates/> </xsl:variable> <xsl:apply-templates select="xt:node-set($x)/*"/> </xsl:template> </xsl:stylesheet> ========================================== which produces the above text output if given the original document modulo a spurious xml declaration that may or may not be a bug in xt (I need to check what the spec says about xsl:import producing multiple conflicting xsl:output ) | |
4. | Pipe or chaining |
> Im trying to do two xslt transformations chained after each other. If you can't combine the operations directly, there are two approaches to chaining: 1. Use the node-set extension. The first transformation creates a result tree fragment, you convert this to a node-set using the node-set() extension function, then you process this node-set with the second transformation. It's probably best for each transformation to use a separate mode. 2. Use two stylesheets, and arrange (via the XSLT vendor's published API) to pipe the output of the first as the input to the second. The details will vary for each product. Saxon has an extension <saxon:output next-in-chain="phase2.xsl"> to make this kind of chaining easy. | |
5. | Multiple input to multiple output |
Is it possible to use XSL to process all the XML files in a directory according to one stylesheet and create one output file for each input file? Sebastian wrote surely this is best done with a conventional script? like for i in *.xml do xslprocess $i foo.xsl done or whatever the equivalent in Windows command language is? David C wrote: > Can I by any chance use the document function for this? only if you know in advance what the files are: <xsl:apply templates select="document('file1.xml')"/> <xsl:apply templates select="document('file2.xml')"/> . . . Which is a bit of a pain, in which case it is easier to do for i in *.xml ; do xt $i style.xsl ; done (whatever the nt command line syntax for a loop is, that is (ba)sh syntax) The disadvantage of that is it starts up the java virtual machine and reparses the stylesheet afresh on each input file. This is normally what I do, but what probably I ought to do is instead of running xt from the command line like that, have a small java wrapper program that gets all the files in the directory and passes them to the xt class. Robert gives us: Yes, this is possible using XT. You can invoke XT as follows: xt source_dir stylesheet result_dir XT will apply the stylesheet to each file in the source_dir directory and put the output files in the result_dir directory. The stylesheet should not be in the source_dir. When XT creates an output file, it will use the same file name as the corresponding input file. Let's say that your input XML documents are in the IN directory, and your stylesheet (xlate.xsl) is in the current directory, and you want the output files to be placed in the OUT directory. Then you would execute the following command: xt in xlate.xsl out I don't think that this XT feature is documented. I found out about it by reading the source code of the com.jclark.xsl.sax.Driver class (the 19991102 version of XT). Mitch Christensen adds I would recommend a general purpose Perl script which outputs an XML representation of the directory (optionally recursive). This directory.xml then can be used for any/all file processing from within XSL. An example would be. <directory location="file:///C:/"> <file name="foo" ext="xml" createdate="blah".../> ... <directory location="file:///C:/DOS"> ... </directory> </directory> Once this file exists, you can use the document() function to process files/directories as you like. | |
6. | How to escape the blank or other special chars to create a valid URI |
You need to use URLEncoder with a java extension function.... <xsl:stylesheet xmlns:xsl="http://www.w3.org/1999/XSL/Tranform" version="1.0" xmlns:url="http://www.jclark.com/xt/java/java.net.URLEncoder"> <xsl:if test="extension-function-available('url:encode')"> <a href="component.xml?name={url:encode(.)}"> <xsl:value-of select="."/> </a> </xsl:if> |