james
james

Reputation: 33

XML Text Formatting for XSL Transformation

I hope my title does justice for the question. Please consider the following block of XML and sample block of XSL.

<root>
<level_one>
My first line of text on level_one
<level_two>
My only line of text on level_two
</level_two>
My second line of text on level_one
</level_one>
</root>

<xsl:template match="level_one">
<xsl:value-of select="text()"/>
<br/>
<xsl:apply-templates select="level_two"/>
</xsl:template>

<xsl:template match="level_two">
<xsl:value-of select="text()"/>
<br/>
</xsl:template>

As it stands, the output (modified here for reading) when executing the above is

My first line of text on level_one
<br/>
My only line of text on level_two
<br/>

I'm missing the second line of text on level_one. So I'm wondering two things.

  1. Is the XML valid? From what I know, the answwer is yes, but am I wrong?
  2. How can I modify the XSL in order to get the second line (or even more lines in my case than I've shown)?

Thanks

Upvotes: 3

Views: 314

Answers (3)

Dimitre Novatchev
Dimitre Novatchev

Reputation: 243549

Even without a template matching text(), you can output the two text() node children of the current node (level_one) by replacing:

<xsl:value-of select="text()"/>

with:

<xsl:copy-of select="text()"/>

In XSLT 1.0 it is very important to know that <xsl:value-of select="$someNodeSet"/> produces the string value of only the first node (in document order) of the $someNodeSet node-set.

On the other side:

<xsl:copy-of select="$someNodeSet"/>

copies all nodes contained in $someNodeSet.

Upvotes: 1

Michael Kay
Michael Kay

Reputation: 163587

Use the standard XSLT processing model of recursive descent using xsl:apply-templates.

<xsl:template match="*">
  <xsl:apply-templates/>
</xsl:template>

<xsl:template match="text()">
<xsl:value-of select="."/>
<br/>
</xsl:template>

Using <xsl:value-of select="text()"/> is bad news. In XSLT 1.0 it only displays the first text node (as you have discovered). In XSLT 2.0 it displays all the child text nodes, space separated, but this probably isn't what you want because it will output the first and third sentences before the second. (Actually you haven't said exactly what output you want so I'm having to guess.)

Upvotes: 1

Daniel Haley
Daniel Haley

Reputation: 52888

Is the XML valid? From what I know, the answwer is yes, but am I wrong?

Yes your XML is valid. Also, contrary to a comment above, there is nothing wrong with having mixed content (text and elements mixed together) in XML. It all depends on context and how the XML is used. For example, it would be almost impossible to author technical manuals without mixed content. (A good example is reference elements mixed with text in paragraph elements.)

How can I modify the XSL in order to get the second line (or even more lines in my case than I've shown)?

I'm not sure exactly what you're trying to accomplish, but the reason you're not seeing the second line of text is because you're only matching the first line with the first <xsl:value-of select="text()"/>.

I'm not sure if this would work on your full set of XML data, but you could replace both level_one and level_two templates with one template that matches all text():

  <xsl:template match="text()">
    <xsl:value-of select="."/>
    <br/>
  </xsl:template>

This produces the following output:

  My first line of text on level_one
  <br/>
  My only line of text on level_two
  <br/>
  My second line of text on level_one
  <br/>

You could also narrow the match down by specifying the level_one and level_two parents:

  <xsl:template match="level_one/text()|level_two/text()">
    <xsl:value-of select="."/>
    <br/>
  </xsl:template>

This produces the exact same output, but leaves any other text open for matching in other templates.

Hope this helps.

Upvotes: 0

Related Questions