ebro
ebro

Reputation: 3

Preprocess XSL Stylesheet - include external documents

I need to do a transform on a number of XML files. To do the transforms I have a folder of various xsl stylesheets. I need to to the transform using a Java parser and I do not control the content of any of the stylesheets.

The stylesheets reference eachother with xsl:import statements and they also include css style like so:

<style type="text/css">
    <xsl:value-of select="document('../../common/display.css')" disable-output-escaping="yes"/>
</style>

Simplified example

<?xml version="1.0" encoding="utf-8"?>
<xsl:stylesheet version="1.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform">
    <xsl:import href="../../common/functions.xsl"/>

    <xsl:template match="/">
        <html>
            <head>
                <title>..</title>
                <meta http-equiv="content-type" content="text/html; charset=utf-8"/>
                <style type="text/css">
                    <xsl:value-of select="document('../../common/display.css')" disable-output-escaping="yes"/>
                </style>
            </head>
            <body>
                <xsl:apply-templates/>
            </body>
        </html>
    </xsl:template>
</xsl:stylesheet>

I have managed to include all other xsl files by using the following stylesheet to do a first-pass processing.

<?xml version="1.0" ?>
<xsl:stylesheet xmlns:xsl="http://www.w3.org/1999/XSL/Transform" 
                version="1.0">

<xsl:template match="xsl:include">
  <xsl:copy-of select="document(@href)/xsl:stylesheet/*"/>
</xsl:template>

<xsl:template match="@*|node()">
  <xsl:copy>
    <xsl:apply-templates select="@*|node()"/>
  </xsl:copy>
</xsl:template>

</xsl:stylesheet>

However I cannot figure out how to do the same for the css references. Is it even possible to evaluate the xsl:value-of to either get the value of the string within the call to document() or otherwise get the content of the external css file?

Upvotes: 0

Views: 554

Answers (2)

Michael Kay
Michael Kay

Reputation: 163322

Processing xsl:include the way you are doing it isn't correct acccording to the XSLT specification, for a number of reasons: the copied instructions will have in-scope namespaces different from the original, they will have different values for controlling attributes such as version and exclude-result-prefixes, etc.

Handling xsl:import this way is even more challenging, because of the need to respect import precedence. Basically, there are things you can do in a multi-module stylesheet that can't be done in a single-module stylesheet.

As for calls on document(), to find the calls accurately you will need to parse all the XPath expressions. If the argument to document() is a string literal, then in most cases it should be possible to generate a global variable containing the content of the referenced document, and replace the call on document() by a reference to the variable. (But take care with base URIs).

You haven't actually said what you're trying to achieve by transforming your stylesheets in this way. It's a lot of effort, and I can't see what it accomplishes.

Upvotes: 1

Toshihiko Makita
Toshihiko Makita

Reputation: 1304

If you want access CSS files via XSLT stylesheet, use unparsed-text() function instead of document() function.

https://www.cw3.org/TR/2017/REC-xpath-functions-31-20170321/#func-unparsed-text

doument() function assumes the target as XML file and returns the document-node. unparsed-text() function treats the target as text file and returns the whole contents as xs:string.

However you cannot use it XSLT version 1.0, instead yo should use XSLT 3.0 enabled processor such as Saxon HE.

Upvotes: 1

Related Questions