XSLT 1.0对过滤的XML数据进行排序

时间:2012-07-17 13:35:38

标签: xml xslt sorting xslt-1.0

好的,基于这个问题XSLT 1.0 sort elements我无法弄清楚为什么以下不起作用:

我有以下XML:

<?xml version="1.0" encoding="UTF-8"?>
<viewentries>
    <viewentry>
        <entrydata name="Waste">
            <text>Bric-a-Brac</text>
        </entrydata>
        <entrydata name="Disposal">
            <text/>
        </entrydata>
    </viewentry>
    <viewentry>
        <entrydata name="Waste">
            <textlist>
                <text>Paper</text>
                <text>Glass</text>
            </textlist>
        </entrydata>
        <entrydata name="Disposal">
            <text/>
        </entrydata>
    </viewentry>
        <viewentry>
        <entrydata name="Waste">
            <textlist>
                <text>Paper</text>
                <text>Cans</text>
            </textlist>
        </entrydata>
        <entrydata name="Disposal">
                <text>Washing Machines</text>
                <text>Cars</text>
        </entrydata>
    </viewentry>
</viewentries>

以下XSLT:

<?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:key name="k1" match="entrydata[@name = 'Waste' or @name = 'Disposal']//text" use="concat(ancestor::entrydata/@name, '|', .)"/>

    <xsl:template match="viewentries">
        <categories>
            <xsl:apply-templates/>
        </categories>
    </xsl:template>

    <xsl:template match="viewentry">
        <xsl:apply-templates select="entrydata[@name =  'Waste' or @name = 'Disposal']//text
      [generate-id() = generate-id(key('k1', concat(ancestor::entrydata/@name, '|', .))[1])]">
            <xsl:sort select="."/>
        </xsl:apply-templates>
    </xsl:template>

    <xsl:template match="text[normalize-space() != '']">
        <category type="{ancestor::entrydata/@name}">
            <xsl:apply-templates/>
        </category>
    </xsl:template>

</xsl:stylesheet>

这给出了以下输出:

<?xml version="1.0" encoding="UTF-8"?>
<categories>
    <category type="Waste">Bric-a-Brac</category>
    <category type="Waste">Glass</category>
    <category type="Waste">Paper</category>
    <category type="Waste">Cans</category>
    <category type="Disposal">Cars</category>
    <category type="Disposal">Washing Machines</category>
</categories>

我需要按排序顺序输出:

<?xml version="1.0" encoding="UTF-8"?>
<categories>
    <category type="Waste">Bric-a-Brac</category>
    <category type="Waste">Cans</category>
    <category type="Disposal">Cars</category>
    <category type="Waste">Glass</category>
    <category type="Waste">Paper</category>
    <category type="Disposal">Washing Machines</category>
</categories>

我做错了什么?

修改

似乎只根据<text>的{​​{1}}值而不是所有<entrydata>值进行排序。

但是这个样式表工作正常:

<text>

有人可以解释为什么第一个例子不起作用,但第二个例子没有用。

1 个答案:

答案 0 :(得分:2)

  

任何人都可以解释为什么将排序应用于第一个模板,   但是当它应用于我原来的第二个模板时   问题不是????

这是您的“第二个模板”:

<xsl:template match="text[normalize-space() != '']">
    <category type="{ancestor::entrydata/@name}">
        <xsl:apply-templates>
                <xsl:sort select="."/>            
        </xsl:apply-templates>
    </category>
</xsl:template>

在这里,您希望按字符串值对当前节点的子节点进行排序。

但是,在提供的XML文档中,任何text元素都有一个文本节点子元素 - 因此没有任何要排序的东西!

在此问题和上一个问题中,您提交了相同的错误 - 尝试对必须排序的元素的子项进行排序 - 您排序太晚了。

<强>记住

   <xsl:apply-templates/>

的缩写:

   <xsl:apply-templates select="child::node()"/>

所以,这意味着:将模板应用于我的孩子“ - 不是”将模板应用于我“。

更新:以下是解决问题的正确方法:

<xsl:stylesheet version="1.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform">
 <xsl:output omit-xml-declaration="yes" indent="yes"/>

 <xsl:key name="kCatVal" match="text[text()]" use="concat(../@name, '+', .)"/>

 <xsl:template match="/">
  <categories>
   <xsl:apply-templates select=
    "//text[generate-id()
               =
                generate-id(key('kCatVal',
                                 concat(../@name, '+', .)
                                 )[1]
                            )
                ]">
          <xsl:sort/>
    </xsl:apply-templates>
  </categories>
 </xsl:template>

 <xsl:template match="text">
        <category type="{../@name}"><xsl:value-of select="."/></category>
  </xsl:template>
</xsl:stylesheet>

应用于提供的XML文档

<viewentries>
    <viewentry>
        <entrydata name="Waste">
            <text>Bric-a-Brac</text>
        </entrydata>
        <entrydata name="Disposal">
            <text/>
        </entrydata>
    </viewentry>
    <viewentry>
        <entrydata name="Waste">
            <textlist>
                <text>Paper</text>
                <text>Glass</text>
            </textlist>
        </entrydata>
        <entrydata name="Disposal">
            <text/>
        </entrydata>
    </viewentry>
    <viewentry>
        <entrydata name="Waste">
            <textlist>
                <text>Paper</text>
                <text>Cans</text>
            </textlist>
        </entrydata>
        <entrydata name="Disposal">
            <text>Washing Machines</text>
            <text>Cars</text>
        </entrydata>
    </viewentry>
</viewentries>

产生了想要的正确结果

<categories>
   <category type="Waste">Bric-a-Brac</category>
   <category type="">Cans</category>
   <category type="Disposal">Cars</category>
   <category type="">Glass</category>
   <category type="">Paper</category>
   <category type="Disposal">Washing Machines</category>
</categories>

解释

这种分组需要基于具有两个部分的复合键进行索引。因此,use的{​​{1}}属性被指定为这两个部分的串联,由我们知道不能出现在任何值中的字符连接在一起(以避免在值为0时出现误报)第一个关键组件是第二个关键组件的值的前缀。)