我如何在 XSLT2 中按自然顺序用字母和数字对组进行排序?

How do I sort a group, in natural order, with letters and numbers in XSLT2?

我继承了代码,但我不完全理解为什么它不起作用,但我也希望它能做更多事情。明显的问题是 group-by 永远找不到组,因为它要查找的属性对于每个项目始终是唯一值。除此之外,我还在寻找自然顺序排序。据我所知,我想我可能需要先按字母对组进行排序,然后再按数字对结果进行排序,但我不确定。目前,即使是那里的基本类型也不起作用。现有的 XSLT 代码是:

<xsl:for-each-group select="datafield[@tag='856']" group-by="subfield[@code='u']">
    <xsl:sort select="number(normalize-space(substring-after(subfield[@code='z'], ',')))"/>
    <xsl:copy-of select="."/>
</xsl:for-each-group>

使用此数据:

<collection>
   <record>
      <datafield ind1="4" ind2="1" tag="856">
         <subfield code="u">https://www.example.com/ride02meys</subfield>
         <subfield code="z">Digital item, v.2</subfield>
      </datafield>
      <datafield ind1="4" ind2="1" tag="856">
         <subfield code="u">https://www.example.com/ride01meys</subfield>
         <subfield code="z">Digital item, v.1</subfield>
      </datafield>
      <datafield ind1="4" ind2="1" tag="856">
         <subfield code="u">https://www.example.com/ride12meys</subfield>
         <subfield code="z">Digital item, v.12</subfield>
   </record>
</collection>

我正在尝试获取以下内容,其中排序为 1、2、12,而不是 1、12、2。

<collection>
   <record>
      <datafield ind1="4" ind2="1" tag="856">
         <subfield code="u">https://www.example.com/ride01meys</subfield>
         <subfield code="z">Digital item, v.1</subfield>
      </datafield>
      <datafield ind1="4" ind2="1" tag="856">
         <subfield code="u">https://www.example.com/ride02meys</subfield>
         <subfield code="z">Digital item, v.2</subfield>
      </datafield>
      <datafield ind1="4" ind2="1" tag="856">
         <subfield code="u">https://www.example.com/ride12meys</subfield>
         <subfield code="z">Digital item, v.12</subfield>
   </record>
</collection>

诚然,我在 XSLT 方面很薄弱,所以任何指导都将不胜感激。

提前致谢

要先按点之前的字符串按字母数字顺序对数据进行排序,然后按点后的字符串按数字对数据进行排序,您可以使用两个 xsl:sorts,如下所示:

<xsl:for-each-group select="datafield[@tag='856']" group-by="subfield[@code='u']">
    <xsl:sort select="normalize-space(substring-before(subfield[@code='z'],'.'))" data-type="text"  order="ascending" />
    <xsl:sort select="normalize-space(substring-after(subfield[@code='z'], '.'))" data-type="number" order="ascending" />            
    <xsl:copy-of select="."/>
</xsl:for-each-group>

这假定点 . 可以用作分隔符。如果分隔符不同,则无法使用此方法。

作为旁注:
xsl:for-each-groupgroup-by="subfield[@code='u']" 的效果是只处理每个 subfield 中具有相同值的第一个。如果您需要所有 subfield,请使用 xsl:for-each 遍历 current-group() 或首先使用 xsl:for-each

您应该可以在 xsl:sort 上使用 collation,例如 http://www.w3.org/2013/collation/UCA?lang=en;numeric=yes,如

 <xsl:template match="record">
      <xsl:copy>
        <xsl:for-each-group select="datafield[@tag='856']" group-by="subfield[@code='u']">
            <xsl:sort select="normalize-space(substring-after(subfield[@code='z'], ','))"
               collation="http://www.w3.org/2013/collation/UCA?lang=en;numeric=yes"/>
            <xsl:copy-of select="."/>
        </xsl:for-each-group>          
      </xsl:copy>
  </xsl:template>

https://xsltfiddle.liberty-development.net/ncdD7nt

https://www.w3.org/TR/xslt-30/#uca-collations 阅读有关排序规则的更多信息。

对于旧的 Saxon 9 版本,您可以使用不同的排序规则:

  <xsl:template match="record">
      <xsl:copy>
        <xsl:for-each-group select="datafield[@tag='856']" group-by="subfield[@code='u']">
            <xsl:sort select="normalize-space(substring-after(subfield[@code='z'], ','))"
               collation="http://saxon.sf.net/collation?lang=en;alphanumeric=yes"/>
            <xsl:copy-of select="."/>
        </xsl:for-each-group>          
      </xsl:copy>
  </xsl:template>

http://xsltransform.net/nbiCsZq has an example, documentation is at http://saxonica.com/html/documentation9.6/extensibility/config-extend/collation/implementing-collation.html.