使用XSLT进行排序时忽略'A'和'The'。

3

我希望能够按照忽略任何定冠词和不定冠词“the”和“a”进行排序的列表。例如:

  • The Comedy of Errors
  • Hamlet
  • A Midsummer Night's Dream
  • Twelfth Night
  • The Winter's Tale

我认为在XSLT 2.0中,可以按照以下方式实现:

<xsl:template match="/">
  <xsl:for-each select="play"/>
    <xsl:sort select="if (starts-with(title, 'A ')) then substring(title, 2) else
                      if (starts-with(title, 'The ')) then substring(title, 4) else title"/>
    <p><xsl:value-of select="title"/></p>
  </xsl:for-each>
</xsl:template>

然而,我想要使用浏览器内处理,因此必须使用XSLT 1.0。有没有办法在XSLT 1.0中实现这一点?


4
通常正确的方法是为每个元素存储一个“排序标题”,因为规则可以变得非常复杂,甚至涉及其他语言(例如,“Die”是一篇文章,在德语中应该被忽略,但“Die Hard”不应该被归类到“H”下,即使在德语索引中找到)。《仲夏夜之梦》的排序标题将是“Midsummer Night's Dream, A”。 - Joachim Sauer
我应该提到,starts-with()在XLST 1.0中可用,但if-then-else不可用... - ChrisV
@Joachim - 你说得没错,但我需要使用现有数据,没有资源来维护并行排序字段;Gart的快速脏解决方案正是我所需要的 - 不过你的评论也很好。 - ChrisV
1
好问题!(+1)。请查看我的答案,其中包含完整的解决方案。 - Dimitre Novatchev
2个回答

5
这个转换:
<xsl:template match="plays">
 <p>Plays sorted by title: </p>
    <xsl:for-each select="play">
      <xsl:sort select=
      "concat(@title
               [not(starts-with(.,'A ') 
                  or 
                   starts-with(.,'The '))],
              substring-after(@title[starts-with(., 'The ')], 'The '),
              substring-after(@title[starts-with(., 'A ')], 'A ')
              )
     "/>
      <p>
        <xsl:value-of select="@title"/>
      </p>
    </xsl:for-each>
</xsl:template>

应用于此XML文档时

产生所需的正确结果

<p>Plays sorted by title: </p>
<p>Barber</p>
<p>The Comedy of Errors</p>
<p>CTA &amp; Fred</p>
<p>Hamlet</p>
<p>A Midsummer Night's Dream</p>
<p>Twelfth Night</p>
<p>The Winter's Tale</p>

第二个出色的解决方案,Dimitre,避免了Gart解决方案中的数学问题 - 也谢谢你!由于我必须稍微思考一下,为了其他人的利益,我会补充说明:例如对于《冬天的故事》,它将排序的值将是“Winter's TaleThe Winter's Tale”。 - ChrisV
@ChrisV:是的,这种解决方案的优点在于它更简单,减少了算术错误的机会。无论排序键看起来多么奇怪,都不会影响最终输出的值。 - Dimitre Novatchev
如果“The”出现在文本中间,比如“…Something The Something…”(抱歉,想不出真实例子),可能会出现问题。此外,在一般情况下,“An”的冠词也应相应处理。 - Gart
@Gart:当然可以。但是这个问题严格说来是要求文章在剧本开头--为了排序而消除任何中间单词是没有意义的。 - Dimitre Novatchev
我发现一个边缘情况,即当要排序的项目以"CTA & Fred"的形式出现时,条目将基于&进行排序。这不是"The "的问题,而只是更容易匹配的"A "的问题。 - Jason Aller
@JasonAller,感谢您的报告。请查看编辑后的答案中的修复方法。 - Dimitre Novatchev

2
这是我会做的方法:
<xsl:template match="plays">
    <xsl:for-each select="play">
      <xsl:sort select="substring(title, 1 + 2*starts-with(title, 'A ') + 4*starts-with(title, 'The '))"/>
      <p>
        <xsl:value-of select="title"/>
      </p>
    </xsl:for-each>
</xsl:template>

更新: 我忘记在表达式中加1了(经典的一位错误)

starts-with是来自XSLT 1.0的。证明链接:在Google中第一个搜索结果为XSLT 1.0:函数starts-with


问题在于 starts-with 是 XSLT 2.0,我想 - 编辑 我被纠正了! - Phil
1
我在23分钟前发布后立即纠正了自己,只是不想删除原始评论,因为删除自己的错误似乎有些可疑。干杯。 - Phil
优秀的简单、创意的解决方案 Gart - 谢谢! - ChrisV

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接