Tips & Tricks

You'll find in this section useful recipes to use in your own active sheets. If you don't know how to write an active sheet, you'd rather start with the tutorials.

Handling XML

Parsing XML

For XML parsing, RefleX relies on the parsers available in your platform. Parsing is performed thanks to the <xcl:parse> element:

  <xcl:parse name="myDoc" source="file:///path/to/file.xml"/>

The $myDoc variable can then be used for extracting some elements or attributes with XPath, or used for an XSLT transformation. If you don't understand how to achieve this, please refer to the tutorials.

Note that the source to parse doesn't have to be necessarily a local file on the file system, but can be also be located on the Web, on an FTP server, in an XML database, inside a Zip file, within the jar files known by the JVM, etc:

  • source="http://host:port/path/to/file.xml"
  • source="ftp://user:password@host:port/path/to/file.xml"
  • source="xmldb:provider://host:port/path/to/file.xml"
  • source="zip:///path/to/somefile.zip!/path/to/file.xml"
  • source="res:///org/acme/package/file.xml"

In fact, a wide number of protocols and URI schemes are avalaible in RefleX.

See hereafter if you want to use explicitely a SAX parser or a DOM parser.

Validating XML

An XML document can be validated with a DTD while parsing:

  <xcl:parse name="myDoc" source="file:///path/to/file.xml" validate="yes"/>

When an input document is malformed or invalid regarding a schema, the errors can be handled like shown in the "DTD validation" tutorial.

To turn on a validation with a schema, please refer to the documentation of your parser; for example, if you use Apache Xerces, you can set the property "http://apache.org/xml/features/validation/schema" to true. For that purpose, refer to the section "tuning the XML parsing".

If you intend to validate with more accuracy (co-occurence constraints, algorithmic rules, semantic datatypes, etc), you should consider seriously the Active Schema Language, like shown in the "schema tutorials".

Specifying the parsing style (DOM or SAX)

The style of parsing can be specified thanks to the @style attribute of the <xcl:parse> element.
To produce dynamically a SAX or DOM document, the same attribute is available in the <xcl:document> element.

Parsing à la DOM :

  <xcl:parse name="doc" source="file:///path/to/file.xml" style="tree"/>

Parsing à la SAX :

  <xcl:parse name="doc" source="file:///path/to/file.xml" style="stream"/>

The differences are that the SAX document have to be consumed to begin the parsing (deferred parsing), and that XPath expressions can be applied only on DOM documents. However, thanks to the XCL filtering facilities, you will be able to match SAX events with XPath patterns.

See the tutorial about pipelines and filters.

Switching from DOM to SAX (and vice-versa)

You can either transform a DOM source to a SAX result, or explicitely create a new DOM document from a SAX source. In the same way, you can transform a SAX source to a DOM result, or create a new SAX document from a DOM source.

The former technique is based on <xcl:transform> and is detailed hereafter. You have to specify in its @style attribute which kind of document you want to get.

The latter technique is based on <xcl:document> and is the same as copying a fragment, except that the entire document is used. You have to specify in its @style attribute which kind of document you want to get.

Please have a look here.

Creating an XML document from scratch (DOM or SAX)

The <xcl:document> element serves to create a document, its @style attribute is used to specify whether to create a DOM document or a SAX document; XML litterals can be mixed with active tags and XPath expressions surrounded by curly braces:

  <xcl:document name="doc" style="tree">
      <root>
          <xcl:set name="url" value="http://en.wikipedia.org/wiki/Hello_world"/>
          <title>Hello { $who } !</title>
          <xcl:if test="{ $who = 'world' }">
              <xcl:then>
                  <p>This is a standard <a href="{ $url }">welcome message</a>.</p>
              </xcl:then>
          </xcl:if>
      </root>
  </xcl:document>

Examples are available in the tutorial section.

Other instructions can help to create dynamic XML content : <xcl:element>, <xcl:attribute>, <xcl:namespace-declaration>, <xcl:comment>, <xcl:processing-instruction> and <xcl:text>.

Templating (or Active Documents)

XML instructions and XPath expressions to evalutate can be set directly within an XML template. In Active Tags, such Active Sheets are called Active Documents.

[doc/tutorial/misc/templates/template.xcl]

<?xml version="1.0" encoding="iso-8859-1"?>
<the-current-directory><!--this is a litteral--> <xcl:for-each name="file" select="{ io:file('.')/*[@io:is-file] }" xmlns:xcl="http://ns.inria.org/active-tags/xcl" xmlns:io="http://ns.inria.org/active-tags/io"><!--this is an instruction--> <file size="{ string($file/@io:length) }"><!--this is a litteral -->{ name($file) }<!--this is an XPath expression--> </file> </xcl:for-each> </the-current-directory>

Notice that the path to the current directory "." is resolved relatively to its host document, that is to say to the actual template (this helps to resolve resources relatively).

Run with:

 $ java -jar reflex-0.4.0.jar run doc/tutorial/misc/templates/template.xcl

Output:

<?xml version="1.0" encoding="UTF-8"?>
<the-current-directory>
<file size="490">template.xcl</file>
</the-current-directory>

Templates stands usually in a standalone file, but they can also be wrapped in the <xcl:document> element within an active sheet, as shown previously.

Copying XML fragments

An XML node or a set of nodes can be copied to an independant fragment. This is as simple as creating an XML document :

  <xcl:parse name="theNodes" source="file:///path/to/file.xml"/>
  <xcl:document name="aCopy">
    <doc>
      { $theNodes/to//copy }
    </doc>
  </xcl:document>

Now the updates in $aCopy won't be reflected in $theNodes.

Parsing and merging XML fragments

Active Tags can be used to parse indifferently well-formed XML documents (with or without DTD declaration) and XML fragments, that is to say documents that are almost XML documents but that may contain several root elements and/or that have text content around the root(s) element(s).

For this purpose, simply specify mode="lax" inside the <xcl:parse> element.

For example :

  <xcl:parse mode="lax" name="frag1" source="file:///path/to/file1.xml"/>
  <xcl:parse name="frag2" source="file:///path/to/file2.xml"/>
  <xcl:document name="all">
    <doc>
      { $frag1 }
      { $frag2 }
    </doc>
  </xcl:document>

Several files could be processed in the same manner :

  <xcl:document name="all">
    <doc>
      <xcl:for-each name="file" select="{ io:file('file:///path/to/')/*[@io:extension='xml'] }">
        <xcl:parse mode="lax" name="fragment" source="{ $file }"/>
        { $fragment }
      </xcl:for-each>
    </doc>
  </xcl:document>

Tuning the XML parsing

It is possible to plug any JAXP compliant parser to RefleX (please refer to the JAXP documentation).

According to the implementation selected, standard/proprietary options can be set by using parameters with the <xcl:parse> element :

  <xcl:parse name="xml" source="file:///path/to/file.xml">
      <!--a standard SAX feature-->
      <xcl:param name="http://xml.org/sax/features/external-general-entities" value="{ true() }"/>
      <!--a feature of the Xerces parser-->
      <xcl:param name="http://apache.org/xml/features/validation/dynamic" value="{ true() }"/>
      <!--a property of the Xerces parser-->
      <xcl:param name="http://apache.org/xml/properties/dom/document-class-name"
value="org.acme.dom.DocumentImpl"/> </xcl:parse>

The exemple above show how to set a feature and a property to Apache's Xerces. Please refer to the document of your parser.

Transforming XML

Transforming with XSLT

As shown in the picture above, <xcl:transform> serves many purpose:

  • transform XML to HTML with XSLT,
  • transform by copy a DOM tree to a SAX stream,
  • serialize a source to XML,
  • serialize SVG to PNG,
  • transform XML to SVG with XSLT and serialize to PNG,
  • serialize XSLFO to PDF,
  • transform with a compiled stylesheet after Java bytecode generation from XSLT,
  • and many other combinations.

The most common usage is to use an XSLT stylesheet, this is simply performed like this:

<xcl:transform output="file:///path/to/file.html" source="file:///path/to/file.xml"
stylesheet="file:///path/to/file.xsl"/>

Like explained for parsing, a wide number of protocols and URI schemes like http, webdav, zip, xmldb, etc, can be used for the source, the output, and the stylesheet. Character/byte streams are also supported for example if the result of the transformation is the response of an HTTP request (see "Sharing stylesheets" in Web applications). Additionally, a reference to a SAX or DOM document parsed in a previous step can also be specified instead of the URI of a source: source="{ $myDoc }".

If you intend to reuse the stylesheet several times, you'd rather parse it once:

<xcl:parse-stylesheet name="xslt" source="file:///path/to/file.xsl"/>

...and refer the parsed-stylesheet (which is thread-safe):

<xcl:transform output="file:///path/to/file.html" source="file:///path/to/file.xml"
stylesheet="{ $xslt }"/>

Notice that you can also compile XSLT to Java byte code, as explained hereafter.

In Web application, ensure that the parsed-stylesheet has the required scope, as explained later.

In the next sections you'll find other useful use cases.

Passing parameters to XSLT

As part of JAXP, the transform API for XML (trax) allows to plug any compliant XSLT engine.

There are 3 cases to consider :

  • Setting options to the stylesheet

    This can be done in the same way than XML parsing when parsing the stylesheet with the <xcl:parse-stylesheet> element :

      <xcl:parse-stylesheet name="xslt" source="file:///path/to/file.xsl">
          <!--a property of the Xalan XSLT engine-->
          <xcl:param name="http://apache.org/xalan/features/incremental" value="{ true() }"/>
      </xcl:parse-stylesheet>

    The exemple above show how to set a property to Apache's Xalan.

    Ensure that the @stylesheet attribute of the <xcl:transform> element refers to the parsed stylesheet when performing the transformation (see below).

  • Passing parameters to the stylesheet

    A stylesheet (XSLT) may accept external parameters that can be set at runtime :

    <?xml version="1.0" encoding="iso-8859-1"?>
    <xsl:stylesheet version="1.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform"> <xsl:param name="age-of-the-captain" select="number(22)"/> <!-- XSLT templates here... --> </xsl:stylesheet>

    To transmit an external parameter to the stylesheet, you have to specify it in the active sheet:

      <xcl:transform output="file:///path/to/file.html" source="file:///path/to/file.xml"
    stylesheet="{ $xslt }"> <!--set the age of the captain in th XSLT from an environment variable--> <xcl:param name="age-of-the-captain" value="{ number( $sys:env/age ) }"/> </xcl:transform>
  • Overriding the output properties of the stylesheet

    The parameter names bound to the XSLT namespace URI are used to override the output properties specified in the stylesheet (or to set them if they are unspecified in the stylesheet) :

      <xcl:transform output="file:///path/to/file.html" source="file:///path/to/file.xml"
    stylesheet="{ $xslt }" xmlns:xsl="http://www.w3.org/1999/XSL/Transform"> <xcl:param name="xsl:encoding" value="iso-8859-1"/> <xcl:param name="xsl:indent" value="yes"/> </xcl:transform>

    (don't forget the namespace declaration either on that element or on one of its parent)

Serializing DOM or SAX to an XML file or stream

The DOM or SAX documents built with <xcl:document> or parsed with <xcl:parse> in the previous examples are logic XML views. How to save them to a file ? Simply perform a transformation that copies the document to an output file ; such a transformation act only on the nature of the datas (which are "transformed" to XML tags saved in the file), not on their structure (which is copied).

To achieve this, omit the reference to the stylesheet of the <xcl:transform> element, which means that a copy is expected :

  <xcl:transform output="file:///path/to/myFile.xml" source="{ $myXml }"/>

Of course, the "file" could be replaced by an output stream. You'll see later 2 examples where:

Parameters can be set to the stylesheet, including those that specify the output (method, encoding, DTD, etc). See passing parameters to XSLT. The parameter xsl:method set to the value "xml" (this is the default value) is specifically useful to avoid the serializer producing an ill-formed HTML (by adding non-closed meta-tag elements in the header for example).

Serializing SVG to PNG and XSLFO or HTML+CSS to PDF

An XML source, a DOM tree, or a SAX stream can be transformed to GIF, PNG or PDF if the source is SVG or XSLFO or even (X)HTML+CSS, or if the source is transformed with XSLT to one of this format. You'll find hereafter the serializers available, and how to add or replace your own.

Below are the source code of an XML document, a stylesheet that can transform the data to SVG, the resulted SVG, and the rasterized picture:

[doc/tutorial/transform/svg/sales.xml]

<?xml version="1.0" encoding="iso-8859-1"?>
<Sales> <Report Year="2009"> <Summary Region="North"> <Q1 TotalSales="10"/> <Q2 TotalSales="150"/> <Q3 TotalSales="140"/> <Q4 TotalSales="180"/> </Summary> <Summary Region="East"> <Q1 TotalSales="110"/> <Q2 TotalSales="70"/> <Q3 TotalSales="100"/> <Q4 TotalSales="50"/> </Summary> <Summary Region="West"> <Q1 TotalSales="60"/> <Q2 TotalSales="140"/> <Q3 TotalSales="130"/> <Q4 TotalSales="200"/> </Summary> <Summary Region="South"> <Q1 TotalSales="100"/> <Q2 TotalSales="140"/> <Q3 TotalSales="80"/> <Q4 TotalSales="95"/> </Summary> </Report> </Sales>

[doc/tutorial/transform/svg/chart.xsl]

<?xml version="1.0" encoding="iso-8859-1"?>
<xsl:stylesheet version="1.0" exclude-result-prefixes="data" xmlns="http://www.w3.org/2000/svg" xmlns:xsl="http://www.w3.org/1999/XSL/Transform" xmlns:data="data:draw parameters by region"> <xsl:output method="xml" media-type="image/svg+xml" encoding="iso-8859-1" indent="yes"/> <xsl:strip-space elements="*"/> <data:Regions> <data:Region name="North" barColor="#B8CCDE" startXPosition="80"/> <data:Region name="East" barColor="#FFFFCC" startXPosition="180"/> <data:Region name="West" barColor="#9999FF" startXPosition="280"/> <data:Region name="South" barColor="#993366" startXPosition="380"/> </data:Regions> <xsl:variable name="Regions" select="document('')/*/data:Regions"/> <xsl:param name="title" select="'Sales Report for ACME'"/> <xsl:template match="/"> <svg width="14cm" height="10cm"> <!--Heading--> <text x="5" y="28" text-anchor="start" font-weight="bolder" font-size="20"
fill="maroon" text-decoration="underline"> <xsl:value-of select="$title"/> Year <xsl:value-of select="/Sales/Report/@Year"/> </text> <!--Caption (Vertical)--> <g transform="translate(40, 100) rotate(270, 0, 0)"> <text x="-98" y="5" text-anchor="middle" font-weight="bolder" font-size="16"
fill="black"> Sales (Hundred Thousand €) </text> </g> <!--Caption (Horizontal)--> <text x="190" y="350" font-size="16" font-weight="bolder" fill="black"> Region (Per Quarter) </text> <!--Lines--> <g stroke="gray" stroke-width="1"> <line x1="70" y1="300" x2="490" y2="300"/> <line x1="70" y1="300" x2="70" y2="70"/> </g> <!--Data Charts--> <xsl:apply-templates/> </svg> </xsl:template> <xsl:template match="Summary"> <xsl:variable name="startXPosition"
select="$Regions/data:Region[@name=current()/@Region]/@startXPosition"/> <text x="{$startXPosition+10}" y="320" font-weight="bolder" font-size="16"
fill="#225C91"> <xsl:value-of select="@Region"/> </text> <xsl:apply-templates/> </xsl:template> <xsl:template match="Q1 | Q2 | Q3 | Q4"> <xsl:variable name="qYPos" select="300 - @TotalSales"/> <xsl:variable name="barColor"
select="$Regions/data:Region[@name=current()/../@Region]/@barColor"/> <xsl:variable name="startXPosition"
select="$Regions/data:Region[@name=current()/../@Region]/@startXPosition"/> <rect stroke-width="1" stroke="black" width="15" fill="{$barColor}"
x="{$startXPosition + 20 * position() -20}" y="{$qYPos}" height="{@TotalSales}"/> <text x="{$startXPosition + 20 * position() -20}" y="{$qYPos - 5}" font-size="11"
fill="black"> <xsl:value-of select="@TotalSales"/> </text> </xsl:template> </xsl:stylesheet>

[doc/tutorial/transform/svg/sales.svg]

<?xml version="1.0" encoding="iso-8859-1"?>
<svg height="10cm" width="14cm" xmlns="http://www.w3.org/2000/svg"> <text text-decoration="underline" fill="maroon" font-size="20" font-weight="bolder"
text-anchor="start" y="28" x="5">Sales Report for ACME Year 2009</text> <g transform="translate(40, 100) rotate(270, 0, 0)"> <text fill="black" font-size="16" font-weight="bolder" text-anchor="middle" y="5"
x="-98"> Sales (Hundred Thousand €) </text> </g> <text fill="black" font-weight="bolder" font-size="16" y="350" x="190"> Region (Per Quarter) </text> <g stroke-width="1" stroke="gray"> <line y2="300" x2="490" y1="300" x1="70"/> <line y2="70" x2="70" y1="300" x1="70"/> </g> <text fill="#225C91" font-size="16" font-weight="bolder" y="320" x="90">North</text> <rect height="10" y="290" x="80" fill="#B8CCDE" width="15" stroke="black"
stroke-width="1"/> <text fill="black" font-size="11" y="285" x="80">10</text> <rect height="150" y="150" x="100" fill="#B8CCDE" width="15" stroke="black"
stroke-width="1"/> <text fill="black" font-size="11" y="145" x="100">150</text> <rect height="140" y="160" x="120" fill="#B8CCDE" width="15" stroke="black"
stroke-width="1"/> <text fill="black" font-size="11" y="155" x="120">140</text> <rect height="180" y="120" x="140" fill="#B8CCDE" width="15" stroke="black"
stroke-width="1"/> <text fill="black" font-size="11" y="115" x="140">180</text> <text fill="#225C91" font-size="16" font-weight="bolder" y="320" x="190">East</text> <rect height="110" y="190" x="180" fill="#FFFFCC" width="15" stroke="black"
stroke-width="1"/> <text fill="black" font-size="11" y="185" x="180">110</text> <rect height="70" y="230" x="200" fill="#FFFFCC" width="15" stroke="black"
stroke-width="1"/> <text fill="black" font-size="11" y="225" x="200">70</text> <rect height="100" y="200" x="220" fill="#FFFFCC" width="15" stroke="black"
stroke-width="1"/> <text fill="black" font-size="11" y="195" x="220">100</text> <rect height="50" y="250" x="240" fill="#FFFFCC" width="15" stroke="black"
stroke-width="1"/> <text fill="black" font-size="11" y="245" x="240">50</text> <text fill="#225C91" font-size="16" font-weight="bolder" y="320" x="290">West</text> <rect height="60" y="240" x="280" fill="#9999FF" width="15" stroke="black"
stroke-width="1"/> <text fill="black" font-size="11" y="235" x="280">60</text> <rect height="140" y="160" x="300" fill="#9999FF" width="15" stroke="black"
stroke-width="1"/> <text fill="black" font-size="11" y="155" x="300">140</text> <rect height="130" y="170" x="320" fill="#9999FF" width="15" stroke="black"
stroke-width="1"/> <text fill="black" font-size="11" y="165" x="320">130</text> <rect height="200" y="100" x="340" fill="#9999FF" width="15" stroke="black"
stroke-width="1"/> <text fill="black" font-size="11" y="95" x="340">200</text> <text fill="#225C91" font-size="16" font-weight="bolder" y="320" x="390">South</text> <rect height="100" y="200" x="380" fill="#993366" width="15" stroke="black"
stroke-width="1"/> <text fill="black" font-size="11" y="195" x="380">100</text> <rect height="140" y="160" x="400" fill="#993366" width="15" stroke="black"
stroke-width="1"/> <text fill="black" font-size="11" y="155" x="400">140</text> <rect height="80" y="220" x="420" fill="#993366" width="15" stroke="black"
stroke-width="1"/> <text fill="black" font-size="11" y="215" x="420">80</text> <rect height="95" y="205" x="440" fill="#993366" width="15" stroke="black"
stroke-width="1"/> <text fill="black" font-size="11" y="200" x="440">95</text> </svg>

The <xcl:transform> element support automatic serialization of the output according to its MIME type (after an optional XSLT transformation); for example, an SVG input can be serialized to PNG if the MIME type is set to image/png; similarly, an XSLFO input can be serialized to PDF if the MIME type is set to application/pdf.

The MIME type can been specified in order of preference:

  1. as an attribute of the <xcl:transform> element:
        <xcl:parse name="sales" source="sales.svg" style="stream"/>
        <!--simply SVG to JPEG-->
        <xcl:transform mime-type="image/jpeg" output="salesSAX-svg.jpeg" source="{ $sales }"/>
  2. as an output property inside the stylesheet:
        <xcl:parse name="sales" source="sales.xml" style="stream"/>
        <!--XSLT with <xsl:output media-type="image/jpeg">-->
        <xcl:transform output="salesSAX-xsl.jpeg" source="{ $sales }" stylesheet="chart-jpeg.xsl"/>

The concrete serializers currently available in the full distribution of RefleX are Batik SVG Toolkit, FOP, and CSS2XSLFO. If you want to plug to RefleX other serializers, or change the default implementations, please refer to "customizing RefleX".

Setting parameters to SVG and XSLFO serializers

FOP and Batik can be invoked with various parameters according to the output expected. In RefleX, those parameters are exposed as QName and can be set as parameters:

    <xcl:transform mime-type="image/tiff" output="sales-xml-bgcolor.tiff" source="sales.xml"
stylesheet="chart.xsl"> <xcl:param name="bk:background-color" value="240,220,240" xmlns:bk="http://xmlgraphics.apache.org/batik"/> </xcl:transform>

For Batik, the namespace URI of the parameters is "http://xmlgraphics.apache.org/batik".

ParameterTypeFormatComment
bk:background-color 3 or 4 comma-separated #xs:byteAllRGBα
bk:force-transparent-white #xs:booleanDefault: false
bk:allowed-script-types comma-separated #xs:stringDefault: "text/ecmascript, application/java-archive"; use "*" to allow all script types
bk:alternate-stylesheet #xs:string
bk:area-of-interest 4 comma-separated positive #xs:floatA rectangle boundaries
bk:constrain-script-origin #xs:booleanDefault: true
bk:default-font-family #xs:stringDefault: "Arial, Helvetica, sans-serif"
bk:execute-onload #xs:booleanDefault: false
bk:height #xs:float
bk:language #xs:stringDefault: "en"
bk:max-height #xs:float
bk:max-width #xs:float
bk:media #xs:string
bk:pixel-unit-to-millimeter #xs:floatDefault: 0.264583
bk:snapshot-time #xs:float
bk:user-stylesheet-uri #xs:string
bk:width #xs:float
bk:quality 0 ≤ #xs:float ≤ 1JPEG
bk:gamma #xs:floatPNG
bk:indexed #xs:integer
bk:compression-method #xs:stringTIFFValues: "none", "packbits", "jpeg" etc; Default: "none"
bk:force-transparent-white #xs:booleanDefault: false
bk:stroke-text #xs:stringPDF, PSValues: "on", "off";
bk:auto-fonts #xs:booleanPDFValues: "true", "false";
bk:device-resolution #xs:integerPDF

For FOP, the namespace URI of the parameters is "http://xmlgraphics.apache.org/fop".

ParameterTypeComment
fop:author #xs:string
fop:base-url #xs:anyURI
fop:creation-date #xs:date
fop:creator #xs:string
fop:font-base-url #xs:anyURI
fop:keywords #xs:string
fop:producer #xs:string
fop:target-resolution #xs:numeric
fop:title #xs:string

Serializing to the standard output

With or without a stylesheet, the <xcl:transform> element can set the output to the the $sys:out $sys:err, or $sys:null property for writing respectively to the standard output, the standard error, or to nothing.

  • Without a stylesheet, to the standard output:
      <xcl:transform output="{ $sys:out }" source="{ $myXml }"/>
  • With a stylesheet, to the standard error:
      <xcl:transform output="{ $sys:err }" source="{ $myXml }" stylesheet="file:///path/to/file.xsl"/>

As usual, don't forget to declare the namespace URI for the sys prefix used in the QName of the property.

Compiling XSLT to Java bytecode

A stylesheet can be compiled to a translet; RefleX supply a wrapper that compile directly XSLT to a Java class that implements the javax.xml.transform.Templates interface:

 $ java -cp reflex-0.4.0.jar org.inria.ns.reflex.xml.translet.Compile (line cut)
doc/tutorial/basic/hello/example.xsl (line cut)
doc/tutorial/transform/translet/WEB-INF/lib/ (line cut)
org.acme.translet.Example example.jar

The command line above will compile the given stylesheet in a Java class packed within a jar file. If this jar file is make reachable by the JVM, it will be possible to refer the relevant class within an active sheet by using the "res" URI scheme like this:

<xcl:transform output="file:///path/to/file.html" source="file:///path/to/file.xml"
stylesheet="res:org.acme.translet.Example"/>

You can examine the application located in the doc/tutorial/transform/translet/ directory: it is a Web application with the actual jar library stored in its WEB-INF/lib/ directory, and with an active sheet that transform an XML source with a compiled stylesheet.

Transforming with a SAX filter

If you have a bunch of SAX filters that typically extends org.xml.sax.helpers.XMLFilterImpl, they can be used instead of using stylesheets; for example with a single SAX filter:

<xcl:transform output="file:///path/to/file.html" source="file:///path/to/file.xml"
stylesheet="res:org.acme.filter.MyXMLFilterImpl"/>

As usual, the relevant class have to be reachable by the JVM.

Arrangements with the source and the output will be performed transparently if they appeared not to be a SAX source and a SAX output.

There is a constraint on the class, that must have either:

  • a static method named newInstance()
  • or a zero-argument constructor
  • or being an interface or an abstract class; in this case a concrete implementation must be available too; please refer to the discovery algorithm.

Making a SAX pipeline

The code below show how to build a process where 2 filters and a stylesheet are applied successively on an input document :

  <xcl:parse name="document" source="file:///path/to/file.xml" style="stream"/>
  <xcl:transform name="result1" source="{ $document }" style="stream"
stylesheet="res:org.acme.filter.MyXMLFilterImpl"/> <xcl:transform name="result2" source="{ $result1 }" style="stream"
stylesheet="res:org.acme.filter.AnotherFilter"/> <xcl:transform output="file:///path/to/file.html" source="{ $result2 }"
stylesheet="file:///path/to/stylesheet.xsl"/>

Each step that has to produce SAX events must specify it explicitely (otherwise the conversion will be made automatically, which means that between each step a DOM document will be built; it is then better to specify explicitely what is expected). In fact, these steps are not performing their task yet, they are creating instead a property that represents the SAX process to perform that will be accomplished later; as the last step isn't designed to produce SAX events, it is those that will cause the starting of the parsing.

Similarly, it is also possible to build a document with <xcl:document> instead of parsing one from a file with <xcl:parse>; simply specify the type="stream" when using the <xcl:document> element.

Filtering XML documents and raw text with XPath

Rule-based filters can filter a SAX stream or a non XML text source with XPath patterns. There are many examples in the tutorial section :

XCL filters are working indifferently for DOM and SAX documents.

Other XML processing

Performing XInclusions

An XInclude filter is just a hard-coded filter. You'll find useful examples in the tutorial section, the test of the XCL module and the XOP tests.

Using Native XML Databases

XML Databases supported

RefleX has been deployed in production with a commercial native XML database, and tested with eXist.

If your DB provider is not supported by RefleX, (it can occurs as the XML:DB specifications can be implemented with slightly differences) please let me know.

RefleX intends to support any XML:DB compliant database. You just have to register the suitable XML:DB driver when launching the engine (please refer to the documentation of your database provider):

  • Use the -driver option from the command line interface.
  • Use the driver-class context parameter of the Web deployment descriptor if you use the servlet.
  • Use Class.forName( driverClass ); if you embed RefleX in an application.

XML:DB drivers work similarly to JDBC drivers: they are supposed to register themselves to the relevant manager, which is unfortunately not performed by all drivers. RefleX expect XML:DB drivers to register themselves. If the XML:DB driver of your provider doesn't register itself to the database manager, you'll have to write a wrapper for that purpose; RefleX supplies such a wrapper for eXist (org.inria.ns.reflex.xml.provider.xmldb.exist.XMLDBDriver) ; you are encouraged to use this class instead of those supplied in eXist. For other XML databases that don't register themselves, adapt the Java source code of this class to their drivers.

Ensure that the driver class is reachable by the JVM.

Once done, use the xmldb URI scheme in order to access to XML and binary resources stored in the database, or in order to store new resources; please refer to the I/O module specification. Here is a piece of code that saves an XML file to an XML:DB database:

    <io:file name="source" uri="file:///path/to/resource"/>
    <io:file mime-type="application/xml" name="target"
uri="xmldb:provider://user:pwd@host:port/path/to/resource"/> <io:copy source="{ $source }" target="{ $target }"/>

Binary files can be stored as well in the databases that support them by setting a MIME type not related to XML.

See also the XQuery tutorial to learn how to load a set of files within an XML database.

Submitting XQuery queries

Querying an XML Native Database depends on the query language supported by the provider (XPath, XQuery, proprietary query language, etc). The <io:request> element will use the XPathQueryService of XML:DB for any supported query language.

Since v0.3.0, an additional support for XQuery has been added ; for this purpose, some extensions to the XML:DB API are used : they are available in the xmldb.jar library available in the RefleX distribution (which is a copy of the XML:DB library bundled in eXist). If available, the <io:request> element will use the XQueryService of the extended XML:DB library. If your provider is compatible with this service, you can also use it.

To load a database and run XQuery queries on the database, see the XQuery tutorial.

Here are some short examples :

  <io:request name="result" source="file:///path/to/query.xqy" style="stream"
type="XQueryService"/>

...for submitting an XQuery query and getting a stream result that can be handled with the $result variable.

If the XQuery query declares external parameters (in the XQuery prolog with declare variable $captain-age as xs:integer external;), they can be passed as usual with the <xcl:param> element (parameters can be qualified names; ensure to declare the relevant namespace URIs) :

  <io:request name="result" source="file:///path/to/query.xqy" style="stream"
type="XQueryService"> <xcl:param name="captain-age" value="{ number(33) }"/> <xcl:param name="ex:hello" value="Hello world !" xmlns:ex="http://example.org/foo"/> </io:request>

The XQuery queries can also be expressed inline if you omit the @source attribute; for that purpose, write your query in the @query attribute (since you have to escape XML characters within the query, the former solution is more suitable). See <io:request> for more informations.

In a future release, it will be possible to submit XQuery queries directly on local files.

Designing XML-oriented programs

Please have a look at the XOP test suite : many use cases that involves parsing, validation, XSLT transformation, XInclude processing, error handling, etc are used for testing purpose and can help for your own processes.

Comparing 2 XML documents

This is a job for XUnit and <xunit:assert-node-equals>.

Once 2 nodes or 2 documents have been compared, XUnit supply means to get a report about the differences. There is also an XSLT stylesheet to get it in HTML. Please refer to the XUnit and WUnit sections.

Dealing with non-XML data sources

HTML to XML

If you have to handle ill-formed HTML documents like XML well-formed documents for example to allow applying XPath expressions to them, you have to parse them with an HTML scanner and tag balancer. RefleX supplies one in its full distribution.

Parsing an HTML document with the <xcl:parse-html> element becomes as simple as parsing an XML document with the <xcl:parse> element :

  <xcl:parse-html name="htmlFile" source="file:///path/to/file.html"/>

If you have to change one of the settings of CyberNeko, simply use them as parameters :

  <xcl:parse-html name="htmlFile" source="file:///path/to/file.html">
      <!--specify explicitely the encoding: -->
      <xcl:param name="http://cyberneko.org/html/properties/default-encoding" value="ISO-8859-1"/>
      <!--ignore the character encoding specified within
          <meta http-equiv='Content-Type' content='text/html;charset=...'>
      -->
      <xcl:param name="http://cyberneko.org/html/features/scanner/ignore-specified-charset"
value="{ true() }"/> </xcl:parse-html>

Note that by default, whatever was used in the source, elements will appear in uppercase and attributes in lowercase, according to HTML DOM specification. Getting an HTML element with XPath can be done with an expression like this : $htmlFile//FORM[@name='login'].

Since the client emulator of WUnit will supply elements name in lower case, you can also explicitely specify to parse HTML documents in lower case:

  <xcl:parse-html elems-name="lower" name="htmlFile" source="file:///path/to/file.html"/>

You'll find numbers of useful examples in WUnit.

XML fragments to XML

Read this.

SQL to XML

Mapping an SQL request to an XML data structure is often performed thanks to proprietary mechanisms. Unfortunately, they are often limited if the expected XML structure is a little complex.

See the tutorial to learn how RefleX maps SQL requests to arbitrary complex XML structures.

LDAP to XML

There is no example ready to run here as it is not obvious to install an LDAP service for testing purpose. However, if you have a corporate LDAP directory, you can experiment it anyway like explained below.

First of all, unlike with RDBMS, existing standards like DSML v2 allow mapping LDAP query results to XML, and neither Active Tags nor RefleX are doing something special for it. The only thing to do is to download the suitable driver, like those proposed in the "dependencies" section, and install the JAR library like the others. If you don't use a DSML v2 driver, please follow these instructions.

As the LDAP query result is like an XML file, the sole thing to do is to parse it in order to get an XML document in the DSML v2 format :

  <xcl:parse name="dsml-result" source="ldap://[host]:[port]/[ldap-query]"/>
  <xcl:transform output="{ $sys:out }" source="{ $dsml-result }"/>

Text to XML

It is possible to use a filter that produces SAX events from a text stream. The most usable built-in filter defined in XCL allows to read a stream of text line by line and fire a character event for each line, but other filters are also available (regexp). It is then easy to pipe that filter to a next one that wraps the texts matched inside XML elements.

To parse this built-in filter, simply use :

    <xcl:parse-filter name="lineReader"
source="http://ns.inria.org/active-tags/xcl/filters#LineReader"/>

In RefleX, http://ns.inria.org/active-tags/xcl/filters#LineReader is mapped to a hard-coded filter by the primal catalog; it is possible to invoke that filter directly:

    <xcl:parse-filter name="lineReader"
source="res:org.inria.ns.reflex.xml.filter.helpers.LineReader"/>

Then, such filters can be connected to a pipeline.

See also:

Designing Web applications

Complete Web applications can be designed entirely or partially with Active Tags. For that purpose, RefleX supply a servlet that can handle a Web-oriented active sheet.

Understanding Web mappings

A Web mapping specify how the Web server will handle incoming URLs sent by the client via HTTP. With RefleX, an active sheet will define all those mappings within an HTTP service (<web:service>).

Within such HTTP service, the web mapping (<web:mapping>) that matches the incoming URL will be selected, if any :

  <web:mapping match="^/(.*\.(?:jpg|gif|png))$" method="GET">
    <!--do something-->
  </web:mapping>

The mapping above could match the following URLs :

  • http://www.example.com/img/flower.gif
  • http://www.example.com/monster.png
  • http://www.example.com/photo/machu-picchu.jpg

Each mapping is declared with a regular expression that will be tested upon the incoming URL; when several <web:mapping>s are defined, the first one that matches is applied. By default, the part of the URL that will be tested upon the regular expression is the part between the application name up to the query string (excluded) ; for example, if the starting path of your application is "myApp", then the URL http://www.example.com/myApp/path/to/doc.html?param=value will be processed by the regexp engine with the part /path/to/doc.html ; if your application is deployed on the root of your server (its starting path would be "/"), then the URL http://www.example.com/path/to/doc.html?param=value will be processed by the regexp engine with the part /path/to/doc.html. Whatever is your deployment environment, you can test the part of the URL that has a meaning in the context of your application. Please refer to the manual of your servlet engine for more informations. If you want to test another part or several parts of the incoming URL, use the @use attribute of the <web:mapping> element.

Additionally, if some groups are captured by the regular expressions, they will be supplied thanks to the @web:match attribute of the $web:request property ; with the incoming URLs above, the value of the XPath expression { string($web:request/@web:match) } would be either img/flower.gif, monster.png, or photo/machu-picchu.jpg.

A concrete example is shown below.

Writing the HTTP response

A Web response is an object exposed as an XML item; this object is available with the predefined property $web:response which is of the type #web:x-response.

As mentionned in the relevant documentation, various attributes are available for sending the HTTP response to the client. The most usefull attribute is the @web:output attribute which is of the type #io:output.

Since the <xcl:transform> element can be used to perform a copy or a transformation to a file or a stream of binary data or characters, it is straightforward to send the response back to the client:

  <xcl:transform output="{ value( $web:response/@web:output ) }" source="{ $myXml }"/>

Of course, the source can be a reference to a DOM document, a SAX document, a file, the result of an XQuery query, and a stylesheet can be involved or not in the transformation.

Web properties and Web types

The predefined properties available in the Web module are:

PropertyType
$web:application#web:x-application
$web:service#web:x-service
$web:session#web:x-session
$web:request#web:x-request
$web:response#web:x-response

Their attributes and content can be handled with XPath expressions like if they were XML items.

Handling FORM datas

The Web module defines some variable for handling various Web representations (sessions, cookies, etc) ; the $web:request property (which has the type #web:x-request) contains various attributes that serves various purpose and its children are representing the form datas sent by the client. Form datas can be sent either by the HTTP POST or GET method; in both cases, the datas will be available in the children of the $web:request property.

For exemple, in the mapping that catch the URI http://www.example.com/some/path.html?user=John&dept=Sales, one can refer to the datas in the query string with : { string($web:request/user) } and with { string($web:request/dept) } (don't omit the string() XPath function)

If several parameters with the same name are sent http://www.example.com/some/path.html?user=John&user=Joe&user=Jane&dept=Sales, each of them can be accessed separately : { string($web:request/user[1]) }, { string($web:request/user[2]) }, and { string($web:request/user[last()]) }. Of course, $web:request/user can be still used, it will return the list of all the parameters with that name that one can iterate on.

Uploading files

Files to upload are like any other FORM parameters : they are available within the children of the $web:request property. However, there is a special behaviour implemented for them.

  • In the most common case, where a form is designed to upload a single file AND that the file is the last parameter in the form, the request parameters are all available among the children of the $web:request property.
  • If other parameters are following the first file to upload in the form, they won't be available immediately in order to preserve the streaming nature of the request body. Actually, the user will have to read first the file to upload (for example by copying it), then will have to check if the request has more parameters with value($web:request/@web:next-parameters); if any, they will be appended to the children of the $web:request property until including the next file to upload. And so on until this attribute value is 0.

In both cases, each file to upload is of the type #io:x-file and its content can be read once and only once; it has the special URI scheme "remote" to indicate that it comes from the client (this scheme doesn't denote any protocol, it is just a convenient mean for handling it almost like any other files). Its path is the original name of the file as it has been set by the client navigator. For example, remote://131.254.249.2:34459/theFile.txt is a valid URI of some remote file to upload. However, you don't usually have to bother with the full URI: only the path might be relevant in traditional Web applications.

Note that if the last file to upload has not been read yet and that the value of the @web:next-parameters attribute of the $web:request property is read, the file content will be discarded, since the request body have to be read until the end of the file stream for checking if other parameters are available. The number of the next parameters read is the value returned, 0 means that no more parameters are available (non zero values can only occur with POST methods). If an other file to upload is in the next parameters, the @web:next-parameters attribute should be checked again and so on. Parameters that are read in the body are appended to the child list of the $web:request property as one goes along. Beware that accessing the attribute don't cause forwarding the streaming, it is accessing the attribute value that cause forwarding the streaming (attributes are just handlers). Thus, the attribute value MUST be either explicitely read with the value() function, or implicitely read, for example when the attribute is involved in an arithmetic operation.

The following snippet code consists on saving a set of files to upload in the temporary directory of the server; all files are sent by the client under the same parameter name, "theFile":

  <!-- the response will be a plain text content with the list of files uploaded -->
  <web:mapping match="^/upload\.txt$" method="POST">
      <!-- the position preceding the first parameter to read in the parameter list -->
      <xcl:set name="pos" value="{ number(0) }"/>
      <!-- repeat reading until the body stream is read completely -->
      <xcl:loop test="{ true() }">
          <!-- take the last set of params to read -->
          <xcl:for-each name="param" select="{ $web:request/*[position() > $pos] }">
              <!--unwrapping the value from the attribute-->
              <xcl:set name="file" value="{ value( $param ) }"/>
              <!--ignore non-file parameters-->
              <xcl:if test="{ $file/@io:exists }">
                <xcl:then>
                  <!-- write to the response the name of the file -->
                  <io:write content="{ name( $file ) } uploaded.
"
output="{ value( $web:response/@web:output ) }"/> <!-- copy the file to some tmp dir --> <io:copy source="{ $file }" target="tmp:///uploads/{ name( $file ) }"/> </xcl:then> </xcl:if> </xcl:for-each> <!-- the next loop, start read from the number of items before appending new ones --> <xcl:set name="pos" value="{ count( $web:request/* ) }"/> <!-- using value() cause forwarding the body stream --> <xcl:set name="next" value="{ value( $web:request/@web:next-parameters ) }"/> <!-- no more file to upload ? exit --> <xcl:break xcl:if="{ $next = 0 }"/> </xcl:loop> <!-- number of files uploaded --> <io:write content="Total : { count( $web:request/theFile ) } files. "
output="{ value( $web:response/@web:output ) }"/> </web:mapping>

The form used (that POST to upload.txt):

[www]
upload.html - Web Navigator

Please select the files to upload :



The plain text response from the server :

[www]
upload.txt - Web Navigator
flower.gif uploaded.
boat.png uploaded.
Total : 2 files.

The TMP directory server-side :

tmp:///uploads/flower.gif
tmp:///uploads/boat.png

Sharing XSLT stylesheets

In a mutli-threaded application such as a Web application, it is certainly extremely valuable to do things once when they can be done once. For example, if a stylesheet is involved when processing incoming requests, it is convenient to parse it once and to share it in all the mappings :

  <!--this section will be run only once when the server starts-->
  <web:init>
      <!--notice below the @scope attribute that means that the parsed
          stylesheet will be available to all incoming requests-->
      <xcl:parse-stylesheet name="myXSLT" scope="shared" source="web:///WEB-INF/xslt/transform.xsl"/>
  </web:init>

  <!--when this mapping is selected, the variable $myXSLT will be available-->
  <web:mapping match="^/(.*)\.html$" method="GET">
      <xcl:transform output="{ value( $web:response/@web:output ) }"
source="web:///xml/{ string($web:request/@web:match) }.xml"
stylesheet="{ $myXSLT }"/> </web:mapping>

Parsed stylesheets are thread-safe.

Another option is to compile XSLT to Java bytecode.

Serving static files

A simple copy from the source file to the output stream of the HTTP response is necessary :

  <web:mapping match="^/(.*\.(?:jpg|gif|png))$" method="GET">
      <io:copy source="web:///{ string($web:request/@web:match) }"
target="{ value( $web:response/@web:output ) }"/> </web:mapping>

The web scheme in the URI allows to refer to a source within the scope of the underlying servlet engine. The @web:match attribute of the $web:response property contains what has been captured by the regular expression used in the @match attribute of the <web:mapping> element.

If several groups are captured by the regular expression, each is exposed as an unamed item within the attribute, and accessible with the convenient XPath expression { string($web:request/@web:match/*[n]) } where n is a non nul positive integer.

It is also possible to install another frontal Web server such as Apache that can deliver the static resources, and to map only dynamic resources to your servlet container.

Sending a "redirect"

A redirection can be done by setting some HTTP headers and the right response status. Simply consider the $web:response property as an XML-aware object that can be updated with Active Update (the type of this property is #web:x-response).

  <web:mapping match="[some path to match]" method="GET">
    <xcl:set name="newURL" value="[some URL to redirect to]"/>
    <xcl:append referent="{ $web:response }">
      <xcl:param name="Location" value="{ $newURL }"/>
      <xcl:param name="Keep-Alive" value="timeout=15, max=100"/>
      <xcl:param name="Connection" value="Keep-Alive"/>
      <xcl:attribute name="web:status-code" value="302"/>
    </xcl:append>
  </web:mapping>

Preventing the display of the stack trace

Sometimes a Web application may launch an exception, which causes the stack trace displayed on the client. To avoid this, simply include a fallback instruction :

<?xml version="1.0" encoding="iso-8859-1"?>
<web:service> <web:mapping match="[some path to match]" method="GET"> <!--perform an action that may cause an error 500--> </web:mapping> <xcl:fallback> <web:clear/> <xcl:attribute name="web:status-code" referent="{ $web:response }" value="500"/> <!--display a smart message--> <web:invoke path="/fatal-error.html"/> </xcl:fallback> </web:service>

Don't forget to make a mapping that serves the error page. Please refer to "serving static files".

Testing Web applications automatically with WUnit

Testing a Web application is a pain : a human tester has to follow links, fill forms at hand, and when the application is updated replay the scenario, and perhaps will miss an important test. WUnit can replace advantageously the human user by a robot that can run hundreds of tests without complaining neither making a mistake. WUnit allows to run automatically repeatable scenarii in mass to ensure that your Web application is still reliable during the development process.

With WUnit you can test the kinematics of your Web applications across multi-pages where WUnit will simulate clicks on links and buttons, fill forms and manage cookies for you.

Please have a look at the WUnit documentation.

Other Web tips

Writing an active sheet

RefleX works with an XML document called an Active Sheet that contains the active tags to run.

Designing and running a test suite with XUnit

With XUnit, you will be able :

  • to test your Active Sheets,
  • to test your XSLT templates individually,
  • to test your Java programs that are dealing with XML datas.

Please have a look at the XUnit cookbook.

Choosing the root element

According to the role of the Active Sheet to run, several root elements can be considered :

  • Using RefleX as a general purpose scripting language : a convenient root element can be used, it is the <xcl:active-sheet> element.
  • Sometimes, as PHP, ASP or JSP does, it is convenient to consider a document that contains dynamic (or "active") parts, also know as a "template"; with Active Tags, such document is called an Active Document : it is a special Active Sheet that builds an XML document according to the active tags encountered; the root element can be any element that is not active for the engine, making it a litteral element. By default, if an element is bound to a module known by the engine, it is active, but this behaviour may be tuned explicitely on the root element when it hosts the @exp:disable-prefixes attribute.
  • To define an XCL filter (as you would define an XSLT stylesheet), just use the <xcl:filter> element. XCL filters are like SAX filters: they read entirely an input an pass the result to the next step; unlike SAX filters, XCL filters can act on the stream thanks to XPath patterns; see the tutorial about filters and the XCL specification for more information.
  • For Web applications that run within a servlet, use the <web:service> element.
  • For module definitions, use the <exp:module> element.
  • To define an Active Schema, use the <asl:active-schema> element.
  • For XML catalogs, use the <cat:catalog> element.

Other special purpose root element could be considered with other third-party modules.

Dealing with resources

RefleX uses consistently URIs for accessing resources. It uses both common URI schemes and specific ones for handling various kind of resources.

URIs and resources

An URI is a resource identifier, but the underlying resource might not exist (yet). RefleX doesn't access to the underlying resource except if it is required explicitely (by getting the size of the file for example) or implicitely (by browsing the file system with XPath for example). Consequently, the string representation of directories MUST end with a trailing slash "/" in order to make the resolution upon a relative path effective. Full details are available in the I/O module specification.

Please refer to the troubleshooting section if the engine fails to resolve a relative URL.

General syntax

TypeSyntaxExamples
Hierarchic scheme://user:password@host:port/path/to/resource file:///path/to/file.xml
http://ns.inria.org/active-tags/
Opaque scheme:scheme-specific-part res:org.inria.ns.reflex.xml.filter.XIncludeFilter
Hybrid scheme:subscheme://user:password@host:port/path/to/resource xmldb:exist://localhost:8181/xmlrpc/db/
Nested scheme://user:password@host:port/path/to/resource!/path/to/nested/resource.txt zip:///path/to/file.zip!/path/to/nested/file.xcl

Neither "hybrids" nor "nested" schemes are covered by some RFCs. They are convenient extensions for accessing resources.

URI schemes supported in RefleX

SchemeUsageExamplesRelated
file For accessing local files file:///path/to/file.xml
http For accessing remote files on the Web http://ns.inria.org/active-tags/ https, webdav, webdavs, ftp, ftps
web For accessing resources of the server within a Web application web:///WEB-INF/web.xml
remote For accessing remote files (internal use only) remote://131.254.249.2:34459/theFile.txt
tmp For accessing temporary files tmp:///path/to/file.xml
res For accessing resources from the Java classpath res:///org/inria/ns/reflex/util/xunit/html-report.xsl
res:org.inria.ns.reflex.xml.filter.XIncludeFilter
zip For accessing embedded resources zip:///path/to/pack.zip!/path/to/nested/file.xcl tar, gz, bz2
xmldb For accessing native XML databases xmldb:exist://localhost:8181/xmlrpc/db/

Bundled resources in RefleX

RefleX embeds resources needed for its own functioning. Some of these resources are accessible from a built-in catalog that the processor uses as a fallback catalog.

The embedded resources are principally module definitions and their Active Schemata. Once a validation with an Active Schema is performed, the embedded resources are used automatically when needed.

If necessary, users could handle them directly with the res scheme : res:///org/inria/ns/reflex/processor/xcl/schema.asl. The res scheme is also used for referring compiled resources : res:org.inria.ns.reflex.processor.asl.types.xs.XSSchema ; it can be used when a resource of the type expected is required.
This facility is used by various components of RefleX; a class referred by the res scheme can also be a Java interface or an abstract class. In this case, a concrete implementation will be looked up with the discovery algorithm.

Built-in modules

Built-in schemata

Built-in stylesheets

Built-in catalogs

The buit-in catalog refer all the resources above except the XUnit and WUnit applications that have to be specified explicitely. This can be done by the command line as well as within a Web application. Please refer to the running section, or to the XUnit and WUnit manuals.

Hard-coded resources

Hard-coded resources are ready-to-use compiled classes that can be referred in certain circumstances in the places where an URI (#xs:anyURI) is expected for building a specific object; in this case the underlying class have to be of the type expected.

For this purpose, a special scheme is supplied by RefleX in addition to the common URI schemes supported for building directly instances. For example, a catalog can be supplied in various formats (OASIS catalogs, Active Catalogs...) and locations (file, web, http, ftp...) ; built-in catalogs can also be addressed as well with an URI that uses the special res scheme, like this : res:org.acme.catalog.MyCatalog, which must be in this case an implementation of the org.inria.ns.reflex.processor.catalog.Catalog interface.

Other resources can be delivered with compiled classes ; for example, a compiled schema that will implement the org.inria.ns.reflex.processor.asl.Schema interface.

Just ensure that such classes can be loaded by the JVM.

Types mapping

Here is the list of the classes to extend or implement in order to deliver an instance of a type given.

TypeClassExamples
#xsl:stylesheet javax.xml.transform.Templates file:///path/to/stylesheet.xsl
res:///org/acme/stylesheet.xsl
res:org.acme.translet.Example
org.xml.sax.helpers.XMLFilterImpl res:org.acme.sax.SomeFilter
#cat:catalog org.inria.ns.reflex.processor.catalog.Catalog file:///path/to/oasisCatalog.xml
file:///path/to/activeCatalog.cat
res:///org/inria/ns/reflex/util/xunit/xunit.cat
#xcl:filter org.inria.ns.reflex.xml.filter.Filter file:///path/to/myFilter.xcl
http://www.w3.org/2001/XInclude
res:org.inria.ns.reflex.xml.filter.helpers.LineReader
#exp:module org.inria.ns.reflex.processor.Module file:///path/to/myModule.exp
res:///org/example/com/MyModule.exp
#asl:schema org.inria.ns.reflex.processor.asl.Schema file:///path/to/book.dtd
file:///path/to/users.xsd
res:org.inria.ns.reflex.processor.asl.types.xml.XMLSchema
(note that in this release, DTD, W3C XML Schema and Relax NG are available only by using an XML parser that support them)

Hard-coded schemata (#asl:schema)

The following classes are the hard-coded schemata available in RefleX

Hard-coded catalog (#cat:catalog)

The following class is the hard-coded catalog available in RefleX

Hard-coded filters (#xcl:filter)

A filter is usually defined in an active sheet that has the <xcl:filter> element as root. To chain filters together, the same element is used with the @filter attribute to refer to a parsed filter, get with <xcl:parse-filter>. As explained previsouly, it is also possible for filters to refer to a hard-coded resource in Java ; simply use the class name as an URL instead of the path to the filter ; the class must be an instance of org.inria.ns.reflex.xml.filter.Filter. If you prefer, you can also use one of the aliases URL instead of the name of the class.

  <xcl:parse-filter source="file:///path/to/filter-def.xcl"/>
  <xcl:parse-filter source="res:org.acme.com.filters.MyFilter"/>

Here is the list of the hard-coded filters supplied by the engine :

  • XInclude filter :
    • http://www.w3.org/2001/XInclude
    • http://ns.inria.org/active-tags/xcl/filters#XInclude (alias)
    • res:org.inria.ns.reflex.xml.filter.XIncludeFilter (alias)
  • Line reader :
    • http://ns.inria.org/active-tags/xcl/filters#LineReader
    • res:org.inria.ns.reflex.xml.filter.helpers.LineReader (alias)
  • Regexp-based tokenizer :
    • http://ns.inria.org/active-tags/xcl/filters#Tokenizer
    • res:org.inria.ns.reflex.xml.filter.helpers.Tokenizer (alias)

See also : some examples.

Packed resources

User applications made with RefleX can be packed to a single file (zip, tar...)

It is not necessary to unpack it because RefleX can refer to any resource in the packed-file; for example RefleX can run an Active Sheet by the command line interface :

java org.inria.ns.reflex.ReflexCLI [command] [options] (line cut)
zip:///path/to/pack.zip!/path/to/nested/file.xcl

or :

java org.inria.ns.reflex.ReflexCLI [command] [options] (line cut)
zip:pack.zip!/path/to/nested/file.xcl

or :

java org.inria.ns.reflex.ReflexCLI [command] (line cut)
-c zip:pack.zip!/path/to/nested/catalog.cat (line cut)
zip:pack.zip!/path/to/nested/file.xcl

Please refer to the VFS documentation for further information. You will see that it is possible -for example- to refer a file within a zip file located on a Web server, or an FTP server.

Additionally, resources within the same packed-file can be addressed relatively as if they were unpacked.

Of course, such URIs can be used within active sheets safely :

  <xcl:parse name="myXML" source="zip:///path/to/pack.zip!/path/to/nested/file.xml"/>

Similarly, you can refer to a file within a jar file: jar:///path/to/library.jar!/path/to/nested/file.xml. Notice that the jar scheme and the res scheme are different: the former is basically a kind of "zip" file acessible as long as you localize it, whereas the latter refers to the resources known by the JVM (available in the CLASSPATH); additionally, the res scheme allows to retrieve Java classes.

Embedded resources in Web applications

The web scheme has been designed to resolve files according to the context of a Web application wherever it is really deployed : web:///WEB-INF/myFile.xml.

This scheme is available exclusively when RefleX is used in Web applications with the org.inria.ns.reflex.ReflexServlet class.

   <web:mapping match="^/\d{4}/this\.xml$">
      <io:copy source="web:///WEB-INF/active-sheet.xcl"
target="{ value( $web:response/@web:output ) }"/> </web:mapping>

Embedding text files with XSLT

RefleX provides a hack to insert raw text data while performing an XSLT transformation. For this purpose, the text scheme may be used to wrap the URI in use :

text:[encoding]:uri

If an encoding is specified, it will be used, otherwise the locale encoding will be used.

Examples :

text:iso-8859-1:file:///path/to/file.txt
text::file:///path/to/file.txt

With XSLT :

  <xsl:value-of select="document( 'text:iso-8859-1:file:///path/to/file.txt' )"/>

Notice that if the resource contains a real XML document or fragment, it will be included as raw text.

Customizing RefleX

Serializers available

Serializers are involved in <xcl:transform> operations when a MIME type is specified.

The serializers currently available in the full distribution of RefleX are:

MIME type Input expected
application/pdf XSLFO, HTML+CSS, XML+CSS, SVG
application/postscript
application/vnd.hp-PCLXSLFO, HTML+CSS, XML+CSS
application/x-pcl
image/jpeg SVG
image/png
image/tiff

The concrete bindings are available as a service provided by the serializer factory component, and defined in the subdirectories of META-INF/services/org.inria.ns.reflex.xml.serialize.SerializerFactory/ in reflex-0.4.0.jar. SVG to PDF/Postscript are specific Batik serializers defined in META-INF/services/org.inria.ns.reflex.xml.provider.svg.BatikSerializer/ As explained hereafter, other implementations can replace the default ones supplied in RefleX, or added to support more output formats.

Discovering generic components implementation

Some generic components (such as the serializer factory mentioned previously) are intended to render a concrete service from a generic class name to discover (the class name stands for the name of the service). A lookup is done once for every class name to discover.

An implementation can be render either as a raw class (instance of java.lang.Class) or as a singleton instance (or both across multiple calls). Singletons are instanciated by their method "newInstance()" if they have one, or by their default zero argument constructor. If the singleton fails to instanciate, the client program would still have the possibility to get the raw class and build itself an instance.

To retrieve a concrete service, a lookup key is supplied by the requester. A lookup key is usually the fully qualified name of a class (usually abstract or an interface): org.acme.Foo, and the resolved class name should be a concrete implementation of it.

The lookup key can be supplied with a variant, in order to bind several implementations (this has to be taken in charge by the caller); for example, org.inria.ns.reflex.xml.serialize.SerializerFactory/image/png. Basically, it means that we want a factory that can supply a serializer for "image/png".

An implementation is found from the key supplied as follows:

  1. The value of the system property with the name of the key supplied if it exists and is accessible.
  2. The value of the JNDI property with the name of the key supplied prepend with "java:comp/env/" if it exists and is accessible.
  3. The value of the init parameter of the Web application with the name of the key supplied if it exists and is accessible (in WEB-INF/web.xml:
    <web-app>
        <context-param>...
    ). During its initialization, the servlet MUST have registered itself with a call to the Web registry; note that this can lead to security issues but is acceptable in certain productions environments.
  4. The contents of the file "reflex.properties" of the current directory if it exists.
  5. The contents of the file "$USER_HOME/reflex.properties" if it exists.
  6. The contents of the file "$JAVA_HOME/jre/lib/reflex.properties" if it exists.
  7. The Jar Service Provider discovery mechanism specified in the Jar File Specification. A jar file can have a resource (i.e. an embedded file) such as META-INF/services/package.Class (or META-INF/services/package.Class/variant if the key contains a variant) containing the name of the concrete class to instantiate.
  8. The fallback default implementation, which is given by the META-INF/services/ of reflex-0.4.0.jar (services found with a line of comment that starts with "#", before or ending with a comment that contains "default" will be processed at the end)

The first value found is returned. If one of those method fails, the next is tried.