XT Extensions

1. Where can I find out about the XT extension functions
2. How to pipeline XT processing.
3. xt:nodeset
4. Pipe or chaining
5. Multiple input to multiple output
6. How to escape the blank or other special chars to create a valid URI

1.

Where can I find out about the XT extension functions

Mike Brown

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:

"In XT's current implementation, the definition of a result tree fragment valued variable is evaluated lazily once each time the variable is referenced. So if a definition of a result tree fragment valued variable has side-effects, make sure you reference that variable exactly once."

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.

David Carlisle

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

David Carlisle

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

Mike Kay

> 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

Robert C. Lyons

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

Jon Smirl

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>