dehulst
dehulst

Reputation: 45

XSLT: variables and "empty" labels

I have an XML datafile containing among other things a string of arbitrarily many comma separated values. I want those values to be displayed in a web browser as a list with one value per line. So I wrote an XSLT template that takes this string, displays the first value followed by a linebreak tag (<br/>), properly name-spaced, and resources with the remainder of the string. In effect, the commas are being replaced by HTML <br/> tags.

Now, when I store the result of calling that template in a xsl:variable, and display that through xsl:value-of, then the HTML tags disappear: what is shown is the string minus the commas.

When I display the result directly by having the xsl:call-template in place of the xsl:value-of, all is fine, and the values appear in a list.

So, what's going on?
Is this behavior an implementation artifact, or is it standard XSLT?

Upvotes: 1

Views: 612

Answers (2)

Martin Honnen
Martin Honnen

Reputation: 167716

Use xsl:copy-of instead of xsl:value-of if you want to output nodes (like your br elements), xsl:value-of creates a simple text node with the string value(s) selected.

Here is an example that shows the difference between xsl:value-of and xsl:copy-of, you will note that it is not the use of the variable with newly created br elements that makes the difference, it is simply the use of xsl:value-of that creates a text() node with the string conversion of the selection:

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

  <xsl:output method="html" indent="yes" version="5" doctype-system="about:legacy-doctype"/>

  <xsl:variable name="var">Phrase 1.<br/>Phrase 2.<br/>Phrase 3.</xsl:variable>

  <xsl:template match="/">
    <html>
      <head>
        <title>.NET XSLT Fiddle Example</title>
      </head>
      <body>
          <section>
              <h1>Example 1: value-of</h1>
              <xsl:value-of select="$var"/>
          </section>
          <section>
              <h1>Example 2: copy-of</h1>
              <xsl:copy-of select="$var"/>
          </section>
          <xsl:apply-templates select="//p"/>
          <xsl:apply-templates select="//p" mode="copy-of"/>
      </body>
    </html>
  </xsl:template>

  <xsl:template match="p">
      <section>
          <h1>Example 1: value-of</h1>
          <xsl:value-of select="."/>
      </section>
  </xsl:template>

  <xsl:template match="p" mode="copy-of">
      <section>
          <h1>Example 1: copy-of</h1>
          <xsl:copy-of select="."/>
      </section>
  </xsl:template>

</xsl:stylesheet>

https://xsltfiddle.liberty-development.net/gWmuiJy/1

Output is

Example 1: value-of
Phrase 1.Phrase 2.Phrase 3.
Example 2: copy-of
Phrase 1.
Phrase 2.
Phrase 3.
Example 1: value-of
Line 1.Line 2.Line 3.
Example 1: copy-of
Line 1.
Line 2.
Line 3.

Upvotes: 1

zx485
zx485

Reputation: 29042

It seems that you hit the boundaries of the RTF ("Result tree fragment"):

When you use an XML fragment to initialize a variable or a parameter, then the variable or parameter is of the "result tree fragment" datatype. This is an XSLT 1.0 specific datatype [just like node-set, but slightly different]. A result tree fragment is equivalent to a node-set that contains just the root node.
You cannot apply operators like "/", "//" or predicate on a result tree fragments. They are only applicable for node-set datatypes.
[...]
a) In XSLT 1.0
The resolution of this is to convert the result tree fragment into a node-set. I am not aware of any oracle specific xpath extension functions that can do this trick for you.
You could use EXSLT to achieve this.
b) Use XSLT 2.0
You can code your transformations in XSLT 2.0. XSLT 2.0 deprecates ResultTreeFragments i.e. if you are modeling an XSLT 2.0 transformation, and you create a variable or a parameter that holds a tree fragment, it is implicitly a node sequence.

So without using an XSLT version greater than 1, you're out of luck. So better use XSLT-2.0 or 3.0 to solve this problem.

Is this behavior an implementation artifact, or is it standard XSLT?

It is standard for XSLT-1.0, but not for XSLT-2.0+.

Upvotes: 0

Related Questions