Re: conditional inclusions

Subject: Re: conditional inclusions
From: Jeni Tennison <mail@xxxxxxxxxxxxxxxx>
Date: Wed, 1 Nov 2000 10:01:52 -0400 (EST)

>can one of you guys explain to us something we call "conditional inclusions".
>say what?
>let me try to explain our problem.
>Let's say I have an XMl file which has an element such as:
><include url="file.xml"/>
>This file would be part of the "input tree".
>You would probably say that xsl:include would do the trick, yes but that's
>not my question.

Actually, from your description of the problem, we wouldn't say that
xsl:include would do the trick.  xsl:include, like xsl:import is about
including/importing *stylesheets* into an XSLT stylesheet.  In other words,
xsl:include/xsl:import are what you would use if you wanted to build
modular stylesheets; they aren't what you use to pull in more information
for processing.  For that, you use the document() function.  For example,
you can use document() to pull in information from a particular file and
process it:

  <xsl:apply-templates select="document('file.xml')" mode="include" />

If you have a filename specified within your source XML, such as with your

  <include url="file.xml" />

you can use XPath to access the name of the file, and document() to access
its content:

  <xsl:apply-templates select="document(include/@url)" mode="include" />

>We want to make these inclusions conditional, and than work on that result
><if include="1">
><include url="file1.xml"/>
><include url="file2.xml"/>

It's not particularly clear to me whether the specification of these
conditions is done in your source XML or in your stylesheet.  You could
specify this in your stylesheet using something like:

    <xsl:when test="$include = 1">
      <xsl:apply-templates select="document('file1.xml')" mode="include" />
      <xsl:apply-templates select="document('file2.xml')" mode="include" />

If the above XML is in your source file, then you need a template that
matches 'if' and decides what to do based on its contents:

<xsl:template match="if">
    <xsl:when test="@include = $include">
      <xsl:apply-templates select="document(then/include/@url)"
                           mode="include" />
      <xsl:apply-templates select="document(else/include/@url)"
                           mode="include" />

In the above, I've used xsl:apply-templates on the result of the call to
document() in 'include' mode.  The reason for this is that document()
returns the root node of the XML document that you're accessing, which will
match a template that matches the root node, which is often used as the
base template in a stylesheet.  So, if you had, for example, a template like:

<xsl:template match="/">
  <xsl:apply-templates select="document('file.xml')" />

you'd cause an infinite loop: the template is matched by the root node of
the source document, then templates are applied to the root node of
file.xml, which fires the template again, so templates are applied to the
root node of file.xml, which fires the template again and so on.

Adding a mode means that you can do:

<xsl:template match="/">
  <xsl:apply-templates select="document('file.xml')" mode="include" />

<xsl:template match="/" mode="include">
  <!-- do something else -->

Another way of getting round the problem is to apply templates to the
document element of the accessed document rather than its root node
(although this only works if the document elements of the accessed document
and source document aren't the same).

Of course, you don't have to apply templates at all: you can assign the
root node of the accessed document to a variable and index into it as you
desire, or use xsl:for-each to iterate over its contents.

I hope that this helps,


Jeni Tennison

 XSL-List info and archive:

Current Thread