How can I transform the following XML with XSLT from this:
<root>
<list>
<item label="21(1)">some text</item>
<item label="(2)">some text</item>
</list>
<list>
<item label="a">some text</item>
<item label="b">some text</item>
</list>
</root>
to this:
<root>
<list label="21">
<item label="(1)">some text</item>
<item label="(2)">some text</item>
</list>
<list>
<item label="a">some text</item>
<item label="b">some text</item>
</list>
</root>
So, if there is a number before a parenthesis on th开发者_Python百科e label
attribute of the first item
, that number needs to be aded as the value of the label
attribute for the parent list
item.
The pattern to match the attribute would be something like:
/(\d+)\([^\)]+\)/
As mentioned by Nikolaus you can use the substring-before
and substring-after
XPath functions. A sample XSL transformation would look like this:
<?xml version="1.0" encoding="utf-8"?>
<xsl:stylesheet version="1.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform">
<xsl:output method="xml" indent="yes"/>
<xsl:template match="@* | node()">
<xsl:copy>
<xsl:apply-templates select="@* | node()"/>
</xsl:copy>
</xsl:template>
<xsl:template match="list">
<list>
<xsl:variable name="prefix" select="substring-before(./item/@label, '(')" />
<xsl:if test="$prefix != '' and number($prefix)">
<xsl:attribute name="label">
<xsl:value-of select="substring-before(./item/@label, '(')"/>
</xsl:attribute>
</xsl:if>
<xsl:apply-templates />
</list>
</xsl:template>
<xsl:template match="item">
<item>
<xsl:attribute name="label">
<xsl:variable name="prefix" select="substring-before(@label, '(')" />
<xsl:choose>
<xsl:when test="$prefix != '' and number($prefix)">
<xsl:value-of select="concat('(', substring-after(@label, '('))"/>
</xsl:when>
<xsl:otherwise>
<xsl:value-of select="@label"/>
</xsl:otherwise>
</xsl:choose>
</xsl:attribute>
<xsl:apply-templates />
</item>
</xsl:template>
</xsl:stylesheet>
you can use the xslt function substring-before to get the substring befor '('
This stylesheet:
<xsl:stylesheet version="1.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform">
<xsl:strip-space elements="*"/>
<xsl:template match="node()|@*" name="identity">
<xsl:copy>
<xsl:apply-templates select="node()|@*"/>
</xsl:copy>
</xsl:template>
<xsl:template match="item[1][boolean(number(substring-before(@label,'(')))]">
<xsl:attribute name="label">
<xsl:value-of select="substring-before(@label,'(')"/>
</xsl:attribute>
<xsl:call-template name="identity"/>
</xsl:template>
<xsl:template match="item[1]/@label[boolean(number(substring-before(.,'(')))]">
<xsl:attribute name="label">
<xsl:value-of select="concat('(',substring-after(.,'('))"/>
</xsl:attribute>
</xsl:template>
</xsl:stylesheet>
Output:
<root>
<list label="21">
<item label="(1)">some text</item>
<item label="(2)">some text</item>
</list>
<list>
<item label="a">some text</item>
<item label="b">some text</item>
</list>
</root>
Edit: Compact predicate.
Edit 2: Test number before parentesis. Explicity strip white space only nodes.
This XSLT 1.0 transformation:
<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>
<xsl:apply-templates select="node()|@*"/>
</xsl:copy>
</xsl:template>
<xsl:template match=
"list[number(substring-before(item[1]/@label, '('))
=
number(substring-before(item[1]/@label, '('))
]">
<list label="{substring-before(item[1]/@label, '(')}">
<xsl:apply-templates select="node()|@*"/>
</list>
</xsl:template>
<xsl:template match=
"item[1]/@label[number(substring-before(., '('))
=
number(substring-before(., '('))
]">
<xsl:attribute name="label">
<xsl:value-of select="concat('(',substring-after(.,'('))"/>
</xsl:attribute>
</xsl:template>
</xsl:stylesheet>
when applied on the provided XML document:
<root>
<list>
<item label="21(1)">some text</item>
<item label="(2)">some text</item>
</list>
<list>
<item label="a">some text</item>
<item label="b">some text</item>
</list>
</root>
produces the wanted, correct result:
<root>
<list label="21">
<item label="(1)">some text</item>
<item label="(2)">some text</item>
</list>
<list>
<item label="a">some text</item>
<item label="b">some text</item>
</list>
</root>
精彩评论