Reputation: 15
I would like to transform the following xml:
<root>
<row id="1">
<order>4711</order>
<customer>a</customer>
</row>
<row id="3">
<order>4712</order>
<customer>a</customer>
</row>
<row id="4">
<order>4713</order>
<customer>b</customer>
</row>
<row id="5">
<order>4714</order>
<customer>c</customer>
</row>
</root>
...into the xml below, by dynamically filtering on the value of customer using external parameters
<root>
<row id="1">
<order>4711</order>
<customer>a</customer>
</row>
<row id="3">
<order>4712</order>
<customer>a</customer>
</row>
</root>
I managed to construct the following xsl and the result is as expected, if I transfer the param as filterAt=customer and filterVal=a:
<?xml version="1.0" encoding="utf-8"?>
<xsl:stylesheet version="2.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform">
<xsl:param name="filterVal"/>
<xsl:param name="filterAt"/>
<xsl:output method="xml" indent="yes"/>
<xsl:template match="node()|@*">
<xsl:copy>
<xsl:apply-templates select="node()|@*"/>
</xsl:copy>
</xsl:template>
<xsl:template match="row">
<xsl:if test="*[local-name()=$filterAt]=$filterVal">
<xsl:copy-of select="."/>
</xsl:if>
</xsl:template>
</xsl:stylesheet>
However, I am wondering whether I can also make the template-match argument as an external parameter. My current argument of match is "row". I would like to pass a third parameter called "rowName" and dynamically use it in the match. Is there a way to achieve this?
I tried the following but xmlspy won't even allow it:
<?xml version="1.0" encoding="utf-8"?>
<xsl:stylesheet version="2.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform">
<xsl:param name="filterVal"/>
<xsl:param name="filterAt"/>
<xsl:param name="rowName"/>
<xsl:output method="xml" indent="yes"/>
<xsl:template match="node()|@*">
<xsl:copy>
<xsl:apply-templates select="node()|@*"/>
</xsl:copy>
</xsl:template>
<xsl:template match="$rowName">
<xsl:if test="*[local-name()=$filterAt]=$filterVal">
<xsl:copy-of select="."/>
</xsl:if>
</xsl:template>
</xsl:stylesheet>
Thank you.
Upvotes: 0
Views: 435
Reputation: 15
thanks to @martin-honnen I am able to construct the solution for xsl 2.0 and 3.0
XSL 2.0:
<?xml version="1.0" encoding="utf-8"?>
<xsl:stylesheet version="2.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform">
<xsl:param name="filterVal"/>
<xsl:param name="filterAt"/>
<xsl:param name="rowName"/>
<xsl:output method="xml" indent="yes"/>
<xsl:template match="node()|@*">
<xsl:copy>
<xsl:apply-templates select="node()|@*"/>
</xsl:copy>
</xsl:template>
<xsl:template match="*[local-name()=$rowName]">
<xsl:if test="*[local-name()=$filterAt]=$filterVal">
<xsl:copy-of select="."/>
</xsl:if>
</xsl:template>
</xsl:stylesheet>
XSL 3.0:
<?xml version="1.0" encoding="utf-8"?>
<xsl:stylesheet version="3.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform" xmlns:xs="http://www.w3.org/2001/XMLSchema">
<xsl:param name="filterVal"/>
<xsl:param name="filterAt"/>
<xsl:param name="row-name" as="xs:string" static="yes" select="'row'"/>
<xsl:output method="xml" indent="yes"/>
<xsl:template match="node()|@*">
<xsl:copy>
<xsl:apply-templates select="node()|@*"/>
</xsl:copy>
</xsl:template>
<xsl:template _match="{$row-name}">
<xsl:if test="*[local-name()=$filterAt]=$filterVal">
<xsl:copy-of select="."/>
</xsl:if>
</xsl:template>
</xsl:stylesheet>
Upvotes: 0
Reputation: 167401
In XSLT 2 and later you can use e.g. match="*[local-name() = $filterAt and . = $filterVal"
or perhaps even easier with an empty template to not copy the non matching elements e.g. <xsl:template match="*[local-name() = $filterAt][not(. = $filterVal)]"/>
.
Also in XSLT 3, the current version of XSLT, there are static parameters and shadow attributes (notice the _match
) e.g.
<xsl:param name="row-name" as="xs:string" static="yes" select="'row'"/>
<xsl:template _match="{$row-name}">...</xsl:template>
Upvotes: 1
Reputation: 16666
In XSLT 1.0, template patterns may not use variables. But you can express the condition in an <xsl:when>
element:
<xsl:template match="*" priority="1">
<xsl:choose>
<xsl:when test="local-name()=$rowName">
<xsl:if test="*[local-name()=$filterAt]=$filterVal">
<xsl:copy-of select="." />
</xsl:if>
</xsl:when>
<xsl:otherwise>
<xsl:copy>
<xsl:apply-templates select="node()|@*" />
</xsl:copy>
</xsl:otherwise>
</xsl:choose>
</xsl:template>
Noteworthy points:
<xsl:template match="node()|@*">
when an element node matches both.<xsl:otherwise>
duplicates the content of the <xsl:template match="node()|@*">
template.Upvotes: 1