Reputation: 81
I have some XML that represents two alternative versions of some text and I am using XSLT to perform the modification that selects one or other versions. In addition, one alternative also contains a placeholder that should be replaced with some other bit of text.
The XSLT is generated programmatically and is essentially an identity transformation with a couple of extra templates that perform the necessary tweaks. However, when the XSLT matches the alternative with the placeholder, the placeholder template doesn't get applied and is never filled in.
The actual code uses python's lxml, but I have been mostly testing the XSLT in notepad++ with the XML plugin. The plugin uses libxml2 and libxslt, like lxml, so they shouldn't be any different.
I have tried adding various versions of <xsl:apply-template />
into template 2, but nothing results in the placeholder getting the value that I expect
The following is a very cut down version of the XML:
<sn:text xmlns:sn="http://some.namespace" xmlns="http://www.w3.org/1999/xhtml">
<p>
<sn:alts sn:id="alts_1">
<sn:alt sn:id="alt_1">start 1</sn:alt>
<sn:alt sn:id="alt_2">
<sn:placeholder sn:id="p_1"/> start 2</sn:alt>
</sn:alts> blah blah blah...</p>
</sn:text>
And the following is the generated XSLT:
<xsl:stylesheet version="1.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform" xmlns="http://www.w3.org/1999/xhtml" xmlns:sn="http://some.namespace">
<!--template 1-->
<xsl:template match="sn:placeholder[@sn:id='p_1']">XYZ</xsl:template>
<!--template 2-->
<xsl:template match="sn:alts[@sn:id='alts_1']">
<xsl:value-of select="sn:alt[@sn:id='alt_2']" />
</xsl:template>
<!--identity transform-->
<xsl:template match="*">
<xsl:copy>
<xsl:apply-templates select="@*|node()"/>
</xsl:copy>
</xsl:template>
<xsl:template match="@*|text()|comment()|processing-instruction">
<xsl:copy-of select="."/>
</xsl:template>
</xsl:stylesheet>
The result that I am expecting should be something like:
<sn:text xmlns:sn="http://some.namespace" xmlns="http://www.w3.org/1999/xhtml">
<p>XYZ start 2 blah blah blah...</p>
</sn:text>
Instead, the placeholder is not replaced with "XYZ", but is left out completely:
<sn:text xmlns:sn="http://some.namespace" xmlns="http://www.w3.org/1999/xhtml">
<p> start 2 blah blah blah...</p>
</sn:text>
Update
Thanks for the pointers. It was quite obvious in the end:
<xsl:stylesheet version="1.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform" xmlns="http://www.w3.org/1999/xhtml" xmlns:sn="http://some.namespace">
<xsl:strip-space elements="*"/>
<xsl:output method="xml" indent="yes" />
<!--template 1-->
<xsl:template match="sn:placeholder[@sn:id='p_1']">XYZ</xsl:template>
<!--template 2-->
<xsl:template match="sn:alts[@sn:id='alts_1']">
<xsl:apply-templates select="sn:alt/sn:placeholder"/>
<xsl:value-of select="sn:alt[@sn:id='alt_1']" />
</xsl:template>
<!--identity transform-->
<xsl:template match="*">
<xsl:copy>
<xsl:apply-templates select="@*|node()"/>
</xsl:copy>
</xsl:template>
<xsl:template match="@*|text()|comment()|processing-instruction()">
<xsl:copy-of select="."/>
</xsl:template>
</xsl:stylesheet>
Upvotes: 1
Views: 435
Reputation: 70648
Is the logic you are trying to implement as follows:
In that case, try this XSLT:
<xsl:stylesheet version="1.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform" xmlns="http://www.w3.org/1999/xhtml" xmlns:sn="http://some.namespace">
<!--template 1-->
<xsl:template match="sn:placeholder[@sn:id='p_1']">XYZ</xsl:template>
<!--template 2-->
<xsl:template match="sn:alts[sn:alt[@sn:id='alt_2']]/sn:alt[@sn:id='alt_1']" />
<xsl:template match="sn:*">
<xsl:apply-templates />
</xsl:template>
<!--identity transform-->
<xsl:template match="*">
<xsl:copy>
<xsl:apply-templates select="@*|node()"/>
</xsl:copy>
</xsl:template>
<xsl:template match="@*|text()|comment()|processing-instruction">
<xsl:copy-of select="."/>
</xsl:template>
</xsl:stylesheet>
See http://xsltfiddle.liberty-development.net/ncdD7mo
Upvotes: 0
Reputation: 461
<xsl:stylesheet version = "2.0" xmlns:xsl = "http://www.w3.org/1999/XSL/Transform" xmlns:sn="http://some.namespace" xmlns:html="http://www.w3.org/1999/xhtml">
<xsl:strip-space elements="*"/>
<xsl:output method = "xml" indent = "yes" />
<xsl:template match="sn:text">
<xsl:copy>
<p>
<xsl:apply-templates select="html:p/sn:alts/sn:alt[@sn:id = 'alt_2']"/>
<xsl:apply-templates select="html:p/text()"/>
</p>
</xsl:copy>
</xsl:template>
<xsl:template match="sn:alt[@sn:id = 'alt_2']">
<xsl:text>xyz </xsl:text><xsl:value-of select="."/><xsl:text> </xsl:text>
</xsl:template>
</xsl:stylesheet>
You may try it.
Upvotes: 0
Reputation: 163675
The template isn't applied because you never select the node that it matches in an xsl:apply-templates
instruction. That's because your match="sn:alts"
doesn't apply-templates to its children.
Incidentally, processing-instruction
should be processing-instruction()
.
Upvotes: 1