【问题标题】:XSLT 1.0 sort on filtered XML dataXSLT 1.0 对过滤的 XML 数据进行排序
【发布时间】:2012-07-16 10:39:26
【问题描述】:

好的,基于这个问题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>

我做错了什么?

编辑:

似乎仅基于&lt;entrydata&gt; 的第一个&lt;text&gt; 值而不是所有&lt;text&gt; 值进行排序。

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

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

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

</xsl:stylesheet>

谁能解释一下为什么第一个例子不起作用,而第二个例子起作用。

【问题讨论】:

    标签: xml xslt sorting xslt-1.0


    【解决方案1】:

    谁能解释为什么将排序应用于第一个模板有效, 但是当将它应用到我原来的第二个模板时 质疑它不????

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

    <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>
    

    解释

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

    【讨论】:

    • 好的我明白了,所以我的 元素是 的一部分,因此我需要在这里排序。问题似乎是,如果我在这里排序,如果 有多个元素,它只会选择第一个 元素。
    • @generalexception:我用完整的解决方案更新了答案。这个问题需要通过复合键索引。
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多