3

输入 XML:

<?xml version="1.0" encoding="utf-8" ?>
<infoset>
  <info>
    <title>Bill</title>
    <group>
      <code>state</code>
    </group>
  </info>
  <info>
    <title>Auto</title>
    <group>
      <code>state</code>
    </group>
  </info>
  <info>
    <title>Auto2</title>
  </info>
  <info>
    <title>Auto3</title>
  </info>
  <info>
    <title>Auto5</title>
  </info>
  <info>
    <title>Certificate</title>
    <group>
      <code>Auto4</code>
    </group>
  </info>
  </infoset>

预期输出:

A

Auto2
Auto3
Auto4
   Certificate
Auto5

S
state
   Auto
   Bill

我需要按字母顺序排列标题和代码。如果信息有组,则图块应位于组下。我正在使用 visual studio2010 、 xslt1.0 处理器和 xml 编辑器。

4

1 回答 1

1

XSLT 中的排序是直截了当的。您实际上真正需要知道的是如何“分组”项目。正如 Michael Kay 所评论的,这在 XSLT 2.0 中比在 XSLT 1.0 中容易得多。在 XSLT 1.0 中,您倾向于使用 Muenchian 分组方法,当您第一次看到它时会感到困惑,但通常是最有效的方法。

从您的输出看起来,您正在做两批分组。首先,按第一个字母,然后按组/代码(如果存在)或title

Muenchian Grouping 通过定义一个键来工作,以便快速查找“组”中的所有项目。对于group/codetitle的第一个字母,您可以这样定义

<xsl:key name="letter" match="info" use="substring(concat(group/code, title), 1, 1)"/>

(注意:这是区分大小写的,因此如果您可以混合使用大小写开头的字母,则可能需要使用“翻译”功能)。

如果group/code存在,它将使用它的第一个字母,否则它将选择title的第一个字母。

对于组/代码标题本身,键如下

<xsl:key name="info" match="info" use="title[not(../group)]|group/code"/>

因此,它只使用不存在“组”元素的“标题”元素。

要为您的第一个分组获取不同的首字母,请选择所有信息元素并检查它们是否是给定字母的键中的第一个元素。这样做是这样的

<xsl:apply-templates 
     select="info
             [generate-id() 
              = generate-id(key('letter', substring(concat(group/code, title), 1, 1))[1])]" 
     mode="letter">
  <xsl:sort select="substring(concat(group/code, title), 1, 1)" />
</xsl:apply-templates>

此处使用“模式”是因为最终的 XSLT 必须与模板匹配info

在匹配的模板中,按代码/组标题进行分组,然后您可以执行此操作

<xsl:apply-templates 
     select="key('letter', $letter)
            [generate-id() = generate-id(key('info', title[not(../group)]|group/code)[1])]">
  <xsl:sort select="title[not(../group)]|group/code" />
</xsl:apply-templates>

最后,要输出最后一组中的所有元素,您只需再次使用该键

<xsl:apply-templates select="key('info', $value)[group/code=$value]/title">

这是完整的 XSLT。

<xsl:stylesheet version="1.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform">
  <xsl:output method="text" indent="yes"/>

  <xsl:key name="letter" match="info" use="substring(concat(group/code, title), 1, 1)"/>
  <xsl:key name="info" match="info" use="title[not(../group)]|group/code"/>

  <xsl:template match="/*">
    <xsl:apply-templates select="info[generate-id() = generate-id(key('letter', substring(concat(group/code, title), 1, 1))[1])]" mode="letter">
      <xsl:sort select="substring(concat(group/code, title), 1, 1)" />
    </xsl:apply-templates>
  </xsl:template>

  <xsl:template match="info" mode="letter">
    <xsl:variable name="letter" select="substring(concat(group/code, title), 1, 1)" />
    <xsl:value-of select="concat($letter, '&#10;')" />
    <xsl:apply-templates select="key('letter', $letter)[generate-id() = generate-id(key('info', title[not(../group)]|group/code)[1])]">
      <xsl:sort select="title[not(../group)]|group/code" />
    </xsl:apply-templates>
  </xsl:template>

  <xsl:template match="info">
    <xsl:variable name="value" select="title[not(../group)]|group/code" />
    <xsl:value-of select="concat($value, '&#10;')" />
    <xsl:apply-templates select="key('info', $value)[group/code=$value]/title">
      <xsl:sort select="." />
    </xsl:apply-templates>
  </xsl:template>

  <xsl:template match="title">
    <xsl:value-of select="concat('   ', ., '&#10;')" />
  </xsl:template>
</xsl:stylesheet>

当应用于您的 XML 时,将输出以下内容

A
Auto2
Auto3
Auto4
   Certificate
Auto5
s
state
   Auto
   Bill
于 2013-07-26T07:54:04.993 回答