【问题标题】:Sort XML to XML using XSLT使用 XSLT 将 XML 排序为 XML
【发布时间】:2013-04-24 12:00:58
【问题描述】:

我发现了一些与此类似的问题, 但努力将解决方案“弯曲”到我需要的东西, 很抱歉再次询问。

我有一些这样的 XML:

<?xml version="1.0" encoding="UTF-8"?>

<ns:Root
    xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
    xmlns:ns="urn:Test.Namespace"  
    xsi:schemaLocation="urn:Test.Namespace Test1.xsd"
    >
    <ns:element1 id="001">
        <ns:element2 id="001.1" order="1">
            <ns:element3 id="001.1.1" />
        </ns:element2>
        <ns:element2 id="001.2" order="2">
            <ns:element3 id="001.1.2" />
        </ns:element2>        
    </ns:element1>
    <ns:element1 id="003">
        <ns:element2 id="007.0" order="1">
            <ns:element3 id="007.1.1" />
        </ns:element2>
    </ns:element1>
    <ns:element1 id="002">
        <ns:element2 id="002.1" order="3">
            <ns:element3 id="002.1.1" />
        </ns:element2>
        <ns:element2 id="002.2" order="4">
            <ns:element3 id="002.1.2" />
        </ns:element2> 
    </ns:element1>    
</ns:Root>

我已经编写了这个 XSLT:

<?xml version="1.0" encoding="UTF-8"?>
<xsl:stylesheet version="1.0"
                xmlns:xsl="http://www.w3.org/1999/XSL/Transform"
                xmlns:ns="urn:Test.Namespace"
                >
    <xsl:output indent="no" />
    <xsl:template match="text()[not(string-length(normalize-space()))]"/>
    <xsl:strip-space elements="*"/>

    <xsl:template match="/">
        <xsl:apply-templates>
            <xsl:sort select="/ns:Root/ns:element1/@id" />
            <xsl:copy-of select="." />
        </xsl:apply-templates>
    </xsl:template>

    <xsl:template match="ns:element1">
        <xsl:copy-of select="." />
        <xsl:apply-templates />        
    </xsl:template>

    <xsl:template match="ns:element2">
        <xsl:copy-of select="." />
        <xsl:apply-templates />
    </xsl:template>

    <xsl:template match="ns:element3">
        <xsl:copy-of select="." />
    </xsl:template>

</xsl:stylesheet>

(我从这里抄写了这个大纲how to sort xml?

我想要做的是使用这个 XSLT 按element1id 属性对我的原始 XML 进行排序并生成 XML。 这个想法是,一旦它被排序,我可以用其他一些 XSLT 处理它以获得最终结果。

不幸的是,这并没有给我任何输出,这让我觉得某处有一个非常愚蠢的错字,但我看不到它。

【问题讨论】:

    标签: xml sorting xslt


    【解决方案1】:

    你的问题都在这个匹配的模板这里

    <xsl:template match="/">
        <xsl:apply-templates>
            <xsl:sort select="/ns:Root/ns:element1/@id" />
            <xsl:copy-of select="." />
        </xsl:apply-templates>
    </xsl:template>
    

    首先\ 符号匹配文档级元素,它与根ns:Root 不同,而是一个级别。这意味着当您执行&lt;xsl:apply-templates&gt; 时,所有将选择的是 ns:root 元素,其中只有一个,因此没有必要对其进行排序!

    您可能首先需要像这样匹配根元素,复制它,然后开始对子元素进行排序。

    <xsl:template match="/*">
        <xsl:copy>
            <!-- Code to select and sort childrens -->
        </xsl:copy>
    </xsl:template>
    

    您遇到的下一个问题是排序语句。您正在使用 xpath 表达式 /ns:Root/ns:element1/@id,但这是一个绝对路径,而不是相对路径,因此只会获取文档中第一个 ns:element1 的 @id 属性。

    假设你已经定位在根元素上,并且假设它只有 ns:element1 元素作为子元素,你可以这样做

        <xsl:apply-templates>
            <xsl:sort select="@id" />
        </xsl:apply-templates>
    

    您遇到的最后一个问题是您的 xsl:apply-templates 中有 &lt;xsl:copy-of select="." /&gt; 语句,这是不允许的。您可能应该在此处使用 xsl:copy,如上所示。

    还值得指出的是,如果您还没有意识到,最好使用 XSLT identity transform 复制现有元素,除非您想以某种方式更改它们。这样您就不必为每种特定类型的元素创建模板。

    试试下面的 XSLT

    <?xml version="1.0" encoding="UTF-8"?>
    <xsl:stylesheet version="1.0"
                    xmlns:xsl="http://www.w3.org/1999/XSL/Transform"
                    xmlns:ns="urn:TestNamespace"                >
        <xsl:output indent="yes" />
    
        <xsl:strip-space elements="*"/>
    
        <xsl:template match="text()[not(string-length(normalize-space()))]"/>
    
        <xsl:template match="/*">
            <xsl:copy>
            <xsl:apply-templates select="@*" />
            <xsl:apply-templates>
                <xsl:sort select="@id" />
            </xsl:apply-templates>
            </xsl:copy>
        </xsl:template>
    
      <xsl:template match="@*|node()">
        <xsl:copy>
          <xsl:apply-templates select="@*|node()"/>
        </xsl:copy>
      </xsl:template>
    </xsl:stylesheet>
    

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

    <ns:Root xmlns:ns="urn:Test.Namespace" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
         xsi:schemaLocation="urn:Test.Namespace Test1.xsd">
       <ns:element1 id="001">
          <ns:element2 id="001.1" order="1">
             <ns:element3 id="001.1.1"/>
          </ns:element2>
          <ns:element2 id="001.2" order="2">
             <ns:element3 id="001.1.2"/>
          </ns:element2>
       </ns:element1>
       <ns:element1 id="002">
          <ns:element2 id="002.1" order="3">
             <ns:element3 id="002.1.1"/>
          </ns:element2>
          <ns:element2 id="002.2" order="4">
             <ns:element3 id="002.1.2"/>
          </ns:element2>
       </ns:element1>
       <ns:element1 id="003">
          <ns:element2 id="007.0" order="1">
             <ns:element3 id="007.1.1"/>
          </ns:element2>
       </ns:element1>
    </ns:Root>
    

    【讨论】:

    • 正如您在上面所说明的那样,这工作得很好,我现在已经通过为我的应用程序重新工作来证明。谢谢。我还有一点要学:)
    • 抱歉,当时没有意识到,但我这里的“精简”示例与我的实际应用不同,因为 ns:root 具有除所示属性之外的其他属性。当我使用它进行排序时,这些属性会丢失。
    • 成为 XML 的“菜鸟” 我不确定所有这些解决方案是如何工作的。据我所知,这是 XSLT,它完成了 XML 和 match 属性似乎匹配任何属性或节点,但它似乎不适用于根。我需要做什么才能复制 ns:root 中的任何其他属性?
    • 我很抱歉。我错过了 XSLT 中的一行。正是&lt;xsl:template match="/*"&gt; 专门复制了此处的根元素(另一个模板匹配所有其他元素)。我也添加了跨属性复制的行。
    • 不需要道歉,它不在最初的问题中。谢谢,这是一种享受。
    【解决方案2】:

    是的,这是一个简单的错字。 只需将 XSLT 中的名称空间更改为您在 XML 中使用的名称空间。 - 反之亦然。

    xmlns:ns="urn:Test.Namespace" -> xmlns:ns="urn:TestNamespace"
    

    第二个修复(基于您的评论)仅包括交换。

    <xsl:template match="/">
        <xsl:apply-templates>
            <xsl:sort select="/ns:Root/ns:element1/@id" />
            <xsl:copy-of select="." />
        </xsl:apply-templates>
    </xsl:template>
    

    <xsl:template match="/">
        <xsl:apply-templates select="ns:Root/ns:element1">
            <xsl:sort select="@id" />
        </xsl:apply-templates>
    </xsl:template>
    

    【讨论】:

    • 我已更新我的 XML 以包含更正的命名空间(见上文)。我现在得到输出,但没有排序。
    • 可以按元素排序吗?例如:` title 3title 2title 1title 1 title 3 `如何按title对所有附件和cmets进行排序
    猜你喜欢
    • 2012-11-02
    • 2016-08-24
    • 1970-01-01
    • 1970-01-01
    • 2017-08-29
    • 2023-03-31
    • 2019-12-05
    • 2019-04-11
    • 1970-01-01
    相关资源
    最近更新 更多