开发者

xslt pattern match transformation

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>
0

上一篇:

下一篇:

精彩评论

暂无评论...
验证码 换一张
取 消

最新问答

问答排行榜