Question

I'm new to XSL, as will be obvious, and something very basic has stumped me. Let's say I have an XML document that looks like this:

<?xml version="1.0" encoding="UTF-8"?>
<essay><author>John Stamos</author>
<text>
    <p>In his song "Turn! Turn! Turn!," Bob Dylan quotes the Bible:
    <quotation>"To every thing there is a season, and a time to every purpose under the 
    heaven,"</quotation> which is a well-known quotation from Ecclesiastes.
    </p>
</text>
</essay>

For my current purposes, I want to mark up the text in the <p> element as well as the <quotation> element and print only these. IE, I want the output

    <span id="paragraph">In his song "Turn! Turn! Turn!," Bob Dylan quotes the Bible:
    <span id="quotation">"To every thing there is a season, and a time to every purpose under the 
    heaven,"</span> which is a well-known quotation from Ecclesiastes.</span>

When I use a stylesheet like the following, however, I run into trouble:

<?xml version="1.0" encoding="UTF-8"?>
<xsl:stylesheet xmlns:xsl="http://www.w3.org/1999/XSL/Transform" xmlns:tei="http://www.tei-    
c.org/ns/1.0"
version="1.0">

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

<xsl:template match="p">
    <span id="paragraph"><xsl:value-of select="//p"/></span>
</xsl:template>

<xsl:template match="quotation">
    <span id="quotation"><xsl:value-of select="//quotation"/></span>
</xsl:template>

</xsl:stylesheet>

The quotation template never gets called; p, its parent, takes precedence apparently. How do I do this?

Was it helpful?

Solution

The reason the quotation template never gets called is because you do not tell XSLT to continue processing within the template matching p. All your do is output an element, and so the XSLT processor will not continue doing any template matching for any descendants of the p element. What you need to do is add this line into the template (within the span element) so that XSLT can continue and match the quotation element.

<xsl:apply-templates />

In fact, you also have a problem with this line

<xsl:value-of select="//p"/>

This will actually return all the text under the first p element in document, not necessarily the one you are on. You could change it to this:

 <xsl:value-of select="."/>

But this will include any text within the nest quotation element. However, you don't actually need this xsl:value-of here at all in this case, because XSLT has the concept of built-in templates, which will output the text of any text nodes it finds, and so just doing xsl:apply-templates will handle this.

Try this XSLT

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

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

<xsl:template match="p">
    <span id="paragraph"><xsl:apply-templates /></span>
</xsl:template>

<xsl:template match="quotation">
    <span id="quotation"><xsl:apply-templates /></span>
</xsl:template>

</xsl:stylesheet>
Licensed under: CC-BY-SA with attribution
Not affiliated with StackOverflow
scroll top