I currently have this xsl that is working great
<?xml version="1.0" encoding="utf-8"?>
<xsl:stylesheet version="2.0"
xmlns:xsl="http://www.w3.org/1999/XSL/Transform">
<xsl:output omit-xml-declaration="yes" indent="yes"/>
<xsl:strip-space elements="*"/>
<xsl:template match="node()">
<xsl:copy copy-namespaces="no">
<xsl:copy-of select="@Ccy"/>
<xsl:apply-templates />
</xsl:copy>
</xsl:template>
</xsl:stylesheet>
This essentially re-writes my XML removing all attributes except Ccy. However, I now need to include attributes with the name "name" as well. Id like to either union the attribute names that I would like to keep:
<xsl:copy-of select="@Ccy | @name"/>
Or, ideally, copy all attributes EXCEPT
<xsl:copy-of select="!@BadAttyName"/>
Any ideas??
You can use the following stylesheets:
INPUT:
$more input.xml
<?xml version="1.0"?>
<a>
<b Ccy="123" name="test1" BadAttyNameTest="toRemove1" BadAttyNameTestt="toRemovee1" other="hey1">toto</b>
<b Ccy="456" name="test2" BadAttyNameTest="toRemove2" BadAttyNameTestt="toRemovee2" other="hey2">abc</b>
<b Ccy="789" name="test3" BadAttyNameTest="toRemove3" BadAttyNameTestt="toRemovee3" other="hey3">uvw</b>
</a>
UNION:
::::::::::::::
inputUnion.xsl
::::::::::::::
<?xml version="1.0" encoding="utf-8"?>
<xsl:stylesheet version="1.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform">
<xsl:output omit-xml-declaration="yes" indent="yes"/>
<xsl:strip-space elements="*"/>
<xsl:template match="node()">
<xsl:copy copy-namespaces="no">
<xsl:copy-of select="@Ccy | @name"/>
<xsl:apply-templates />
</xsl:copy>
</xsl:template>
</xsl:stylesheet>
OUTPUT UNION:
$xsltproc inputUnion.xsl input.xml
<a>
<b Ccy="123" name="test1">toto</b>
<b Ccy="456" name="test2">abc</b>
<b Ccy="789" name="test3">uvw</b>
</a>
It will only copy the union of the attributes @Ccy | @name
@Ccy | @name
, the other attributes are not taken into account.
EXCEPT:
::::::::::::::
inputNOT.xsl
::::::::::::::
<?xml version="1.0" encoding="utf-8"?>
<xsl:stylesheet version="1.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform">
<xsl:output omit-xml-declaration="yes" indent="yes"/>
<xsl:strip-space elements="*"/>
<xsl:template match="node()">
<xsl:copy copy-namespaces="no">
<xsl:copy-of select="@*[not(starts-with(name(),'BadAttyName'))]"/>
<xsl:apply-templates />
</xsl:copy>
</xsl:template>
</xsl:stylesheet>
OUTPUT EXCEPT:
$xsltproc inputNOT.xsl input.xml
<a>
<b Ccy="123" name="test1" other="hey1">toto</b>
<b Ccy="456" name="test2" other="hey2">abc</b>
<b Ccy="789" name="test3" other="hey3">uvw</b>
</a>
the syntax @*[not(starts-with(name(),'BadAttyName'))]
will take all attributes that satisfies the condition in the brackets. The condition is all elements that do not start with BadAttyName
, this is created by combining not()
and starts-with()
.
XSLT 2.0 allows
<xsl:copy-of select="@* except @badAttName"/>
and of course it also allows
<xsl:copy-of select="@* except @*[startswith(name(), 'badAttName')]"/>
But for this particular case, using @*[not(....)]
works just as well.
XPath 2 and later (which is the expression language you use with XSLT 2 and later) does have an except
operator so you can use eg <xsl:copy-of select="@* except @foo"/>
to copy all attributes except the foo
attribute or eg <xsl:copy-of select="@* except (@foo, @bar)"/>
to copy all attributes except the foo
and bar
one.
As you want to exclude attributes starting with a certain prefix you could use <xsl:copy-of select="@* except @*[matches(local-name(), '^BadAttyName')]"/>
although the already suggested solution negating the condition with <xsl:copy-of select="@*[not(matches(local-name(), '^BadAttyName'))]"/>
is more compact and easier in that case probably.
The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.