XSL:如何对三位数、连字符分隔的值进行排序?

XSL: How can I sort a three digit, hyphen separated value?

问题

我正在尝试对 rule/@id 的整个值进行排序,其中 @id 的值是一个三值,带连字符的字符串,例如“1-10-12”或“10-15-2” .我试过转换成数字,也试过格式化数字,但没有成功。

代码示例输出仅按最左边的数字排序,子值乱序。

XML 来源:

<rule-mapping name="C">
   <rule id="0-1-1">
      <checker id="checker1"/>
      <checker id="checker2"/>
  </rule>
   <rule id="0-1-10">
      <checker id="checker3"/>
  </rule>
   <rule id="0-1-11">
      <checker id="checker4"/>         
  </rule>
   <rule id="15-1-2">
      <checker id="checker5"/>         
  </rule>
   <rule id="0-1-12">
      <checker id="checker6"/>         
  </rule>
</rule-mapping>

转换片段:

<tbody>
    <xsl:for-each select="rule-mapping/rule">
        <xsl:sort select="substring-before(@id, '-')" data-type="number"/>
        <xsl:sort select="substring-after(@id, '-')" data-type="number"/>

            <row>
              <entry>
                 <xsl:value-of select="@id"/>                                                                   
              </entry>
              <entry>
              <xsl:for-each select="checker">
                <p>
                 <codeph><xsl:value-of select="@id"/></codeph><xsl:text>&#160;</xsl:text>

                </p>
              </xsl:for-each>                                     
              </entry>                                  
            </row>                          
            <xsl:text>&#xA;</xsl:text>
    </xsl:for-each>
</tbody>

预期输出:

    <row>
       <entry>0-1-1</entry>
       <entry>
         <p><codeph>checker1</codeph> </p>
         <p><codeph>checker2</codeph> </p>
       </entry>
    </row>
    <row>
       <entry>0-1-10</entry>
       <entry>
         <p>
          <codeph>checker3</codeph> </p>
       </entry>
    </row>
    <row>
       <entry>0-1-11</entry>
       <entry>
         <p>
          <codeph>checker4</codeph> </p>
       </entry>
    </row>
    <row>
       <entry>0-1-12</entry>
       <entry>
         <p>
          <codeph>checker6</codeph> </p>
       </entry>
    </row>
    <row>
       <entry>15-1-2</entry>
       <entry>
         <p>
          <codeph>checker5</codeph> </p>
       </entry>
    </row>

提前致谢。

你的想法是正确的,但你需要更进一步:

<xsl:sort select="substring-before(@id, '-')" data-type="number"/>
<xsl:sort select="substring-before(substring-after(@id, '-'), '-')" data-type="number"/>
<xsl:sort select="substring-after(substring-after(@id, '-'), '-')" data-type="number"/>

将这三个 xsl:sort 放在一起,它应该按照您想要的方式排序。

本着 XSLT 2.0 / XPath 2.0 的精神,我会像这样使用单个 <xsl:sort/>

  <xsl:sort select=
   "for $n1 in xs:integer(tokenize(@id, '-')[1]),
        $n2 in xs:integer(tokenize(@id, '-')[2]),
        $n3 in xs:integer(tokenize(@id, '-')[3])
      return
        10000*$n1 + 100*$n2 +$n3
   "/>

完整的变换变成:

<xsl:stylesheet version="2.0"  xmlns:xsl="http://www.w3.org/1999/XSL/Transform"
 xmlns:xs="http://www.w3.org/2001/XMLSchema" exclude-result-prefixes="xs">
 <xsl:output omit-xml-declaration="yes" indent="yes"/>

  <xsl:template match="/*">
    <xsl:apply-templates select="rule">
      <xsl:sort select=
       "for $n1 in xs:integer(tokenize(@id, '-')[1]),
            $n2 in xs:integer(tokenize(@id, '-')[2]),
            $n3 in xs:integer(tokenize(@id, '-')[3])
          return
            10000*$n1 + 100*$n2 +$n3
       "/>
        </xsl:apply-templates>
    </xsl:template>

    <xsl:template match="rule">
       <row>
         <entry>
           <xsl:value-of select="@id"/>                                                                   
         </entry>
         <entry>
           <xsl:apply-templates select="checker"/>
         </entry>                                  
       </row>                          
       <xsl:text>&#xA;</xsl:text>
  </xsl:template>

  <xsl:template match="checker">
    <p>
      <codeph><xsl:value-of select="@id"/></codeph><xsl:text>&#160;</xsl:text>
    </p>
  </xsl:template>
</xsl:stylesheet>

并且当此转换应用于提供的源 XML 文档时:

<rule-mapping name="C">
   <rule id="0-1-1">
      <checker id="checker1"/>
      <checker id="checker2"/>
  </rule>
   <rule id="0-1-10">
      <checker id="checker3"/>
  </rule>
   <rule id="0-1-11">
      <checker id="checker4"/>         
  </rule>
   <rule id="15-1-2">
      <checker id="checker5"/>         
  </rule>
   <rule id="0-1-12">
      <checker id="checker6"/>         
  </rule>
</rule-mapping>

产生了想要的正确结果:

<row>
   <entry>0-1-1</entry>
   <entry>
      <p>
         <codeph>checker1</codeph> </p>
      <p>
         <codeph>checker2</codeph> </p>
   </entry>
</row>
<row>
   <entry>0-1-10</entry>
   <entry>
      <p>
         <codeph>checker3</codeph> </p>
   </entry>
</row>
<row>
   <entry>0-1-11</entry>
   <entry>
      <p>
         <codeph>checker4</codeph> </p>
   </entry>
</row>
<row>
   <entry>0-1-12</entry>
   <entry>
      <p>
         <codeph>checker6</codeph> </p>
   </entry>
</row>
<row>
   <entry>15-1-2</entry>
   <entry>
      <p>
         <codeph>checker5</codeph> </p>
   </entry>
</row>