5

I need to generate an XML structure for a fixed number of languages from an input that may or may not contain information for each language. If the information is missing, I need to generate empty elements. The problem is, that I need to iterate over the languages at many places in the output structure.

The easiest way would be to use something resembling

<xsl:variable name="languages" select="en,de,fr">
<xsl:for-each select="$languages">
...
</xsl:for-each>

with the loop appearing wherever I need the language list.

Of course this does not work, because select="en,de,fr" does not define a node-list. With an extension I could use the node-set function, but I am stuck with XSLT-1.0.

Is there any way to define a constant node-set to iterate over?

(This is somehow related to another question where the accepted answer kills many ideas of creating a constant node set, in particular everything that needs sub-element of <xsl:variable/>)

Community
  • 1
  • 1
Harald
  • 4,575
  • 5
  • 33
  • 72

1 Answers1

3

If you want a constant node set rather than one whose contents are calculated by xsl: instructions, then you can do a trick with document('') which gives you access to the XML tree of the stylesheet itself:

<xsl:variable name="languagesLiteral">
  <lang>en</lang>
  <lang>de</lang>
  <lang>fr</lang>
</xsl:variable>

<xsl:variable name="languages"
     select="document('')//xsl:variable[@name='languagesLiteral']/*" />

This only works for static values, if you had for example <xsl:variable name="foo"><xsl:for-each ...> then the node set you get from the document('') trick would be the xsl:for-each element, not the result of evaluating it.

Ian Roberts
  • 120,891
  • 16
  • 170
  • 183
  • Luckily in my use-case only static values are needed. – Harald Apr 03 '14 at 15:14
  • 1
    Well, in the meantime I learned about an ugly side effect: When I loop over $languages, inside the loop I don't seem to be able anymore to access the original document. A `` returns nothing :-( Any idea how to fix this? – Harald Apr 04 '14 at 09:14
  • 2
    @Harald you have to store it away in a variable `` before you enter the for-each (it could be a global variable at the top level of the stylesheet) and use `$root/whatever`. As you've discovered, `/` on its own means the root of the current document, and inside a for-each over `$languages` that means the stylesheet (`document('')`). – Ian Roberts Apr 04 '14 at 09:34
  • @Harald note you'd have exactly the same problem with the `exslt:node-set()` approach - `/` would be the root of the document fragment that was converted to a node set, not the original root of the input. – Ian Roberts Apr 04 '14 at 09:39
  • Thanks a lot. After seeing the `$root` solution, at least this one is obvious, but I was in the completely-puzzled-mode. XSL keeps being a serious time-sink:-( – Harald Apr 04 '14 at 10:06
  • @Harald there will come a moment when it suddenly starts to make sense :-) XSLT requires quite a different way of thinking about your problems if you're used to procedural/OO languages rather than functional ones. – Ian Roberts Apr 04 '14 at 10:10