Andreas Maier
Andreas Maier

Reputation: 3080

Adding Xinclude support to an XSLT stylesheet

I have a large XSLT stylesheet that converts an XML format into HTML. I would like to add support for XInclude in the input XML file. The goal is that each include file can be XSD-validated independently, as well as the including XML file. I have all the changes in the XML schema for that under control (I think); there are only specific XML elements that can be moved out to include files, and there will be only one level of include file nesting. I have that working in the XML editor of Eclipse, it nicely validates both the including file and each include file.

The XSLT stylesheet is used in two ways, and here we get closer to my question:

  1. In a build environment by a Python script that uses lxml for the XSLT transformation. The Python script is integrated into a make-based build environment and into an Ant script for Eclipse.

  2. In an xsl-stylesheet instruction in the including XML file. This is for the case where people want to immediately see the changes they do in any of the XML files, in a Web browser. This has proven to be a very effective environment, so far, so I don't want to loose that.

I was able to get use case 1. working by using the ElementTree.xinclude() method in the Python script. However, that is no solution for use case 2.

Also, I do understand how to write an XSLT stylesheet that performs only the Xinclude resolution, and this could in theory be used as a first transformation, followed by the existing XSLT stylesheet for the XML to HTML conversion. The problem is that the XML file can have only one xsl-stylesheet instruction.

Another idea would be to leave the XInclude resolution to the Web browser. However, I am not aware of any Web browser that supports that. Also, I would hate to have the restriction to use just one particular browser. So far, we support all of the most common browsers.

Another idea would be to add XInclude resolution support into the existing XSLT stylesheet. However, there I am struggling with what is input and what is output, because these are really three stages (XML input as in the files -> FLat XML with Xinclude resolved -> HTML. The XInclude resolving part would need to perform the first transformation and the existing XSLT code would perform the second. I'm not sure that is possible in one stylesheet.

My questions are:

  1. Is there any way how I can get two XSLT stylesheets invoked when opening the (including) XML file with a Web browser ?

  2. Is there any way how I can improve the existing XSLT stylesheet with XInclude support so that it remains a single stylesheet ?

  3. Is there any way in an XSLT stylesheet to modify the input ?

  4. Do Web browsers provide any support in XInclude resolution ?

Thanks Andy

Upvotes: 2

Views: 841

Answers (2)

Steven D. Majewski
Steven D. Majewski

Reputation: 2157

1 Is there any way how I can get two XSLT stylesheets invoked when opening the (including) XML file with a Web browser ?

2 Is there any way how I can improve the existing XSLT stylesheet with XInclude support so that it remains a single stylesheet ?

[3] Is there any way in an XSLT stylesheet to modify the input ?

[4] Do Web browsers provide any support in XInclude resolution ?

Tackling the questions in reverse order because it's easier that way:

(4) I also haven't seen any web browsers that do XInclude expansion.

(3) I don't know what you mean by "modify the input" : XSLT transforms ( or modifies ) the input into an output. Unless you are asking: can you modify the input in one step, and then again transform the output again ? Yes: if the browser supports exslt:node-set, then you can create a variable with the result of one transform, and then select that variable for another transform. You can use modes to select a different set of templates for the different steps.

Something like:

 <xsl:variable name="doc.all">
    <xsl:apply-templates  mode="p1" select="/" />
</xsl:variable>

with a collection of mode="p1" templates, as well as somewhere a template selecting that variable as a node-set:

  <xsl:template match="/" >
    <xsl:apply-templates select="exslt:node-set($doc.all)" />
  </xsl:template>

[ XSLT-2.0 can process node-sets more directly, however no browsers natively support XSLT-2.0 ]

(2) I don't know what your existing stylesheets look like, but probably: YES. You are thinking procedurally when you think about it necessarily being two separate steps to do the XInclude processing and the rest of the xslt. If you are doing XInclude expansion with XSLT, then xinclude is just another set of patterns to match.

You may want something like this template to do the xinclude expansion:

   <xsl:template   match="xi:include[@href][@parse='xml' or not(@parse)]">
        <xsl:apply-templates select="document(@href)/*" />  
    </xsl:template>

modified from the answer to this question : added the "/*" after the document(@href) to avoid calling the root template again on the included documents as well as the base document.

Then include a match="/" template to set up the outer html, and the rest of the transformation patterns to create the inner nodes.

The two steps are implicit here: step one is to redirect the input source to the xi:include/@href when it encounters that element. Step to is to process the nodes in that document according to the other matching templates.

(1) You can only run one stylesheet using the PI, however, you have Javascript in the browser, so as long as you avoid cross domain security issues, you should be able to do things procedurally.

Some points to consider:

I don't know what browsers do if, as the result of one transform, you produce another file with a different directive. Does it continue again ? Might be worth trying. If not, you can explicitly do the processing in javascript and then apply a 2nd transform.

You have xslt, javascript and css support in the browser: your can inject javascript and css into the output. And css can style XML as well as HTML.

Michael Kay has released Saxon CE, which is an XSLT 2.0 implementation compiled into javascript so that it can run in the browser.

Upvotes: 2

innovimax
innovimax

Reputation: 560

You should probably have a look at XProc to do that

It seems your use case it too convoluted to be done in single XSLT

Upvotes: 0

Related Questions