Xslt 重温:对任意XML文档的元素进行递归排序

Xslt 重温:对任意XML文档的元素进行递归排序,xslt,Xslt,我的XSLT传奇中的这一章是这个问题的延伸。感谢所有帮助我走到这一步的人(@Martin Honnen、@Ian Roberts、@Tim C,还有我想念的其他人) 这是我目前的问题: 我在A_v1.xml中重新排序了一些同级,以创建A_v2.xml

我的XSLT传奇中的这一章是这个问题的延伸。感谢所有帮助我走到这一步的人(@Martin Honnen、@Ian Roberts、@Tim C,还有我想念的其他人)

这是我目前的问题:

  • 我在
    A_v1.xml
    中重新排序了一些同级,以创建
    A_v2.xml
    <现在,我认为这两个文件在同一个文件中的版本不同。文件两个文件具有完全相同的内容,只有一些兄弟有不同的顺序。另一种说法是,
    A_v2.xml
    中的每个元素仍然具有与
    A_v1.xml
    中相同的父元素,但现在它可能出现在它以前出现的同级元素之前,也可能出现在它以前出现的同级元素之后
  • 我将
    A_v1.xml
    转换为
    A_v1_transformed.xml
  • 我将
    A_v2.xml
    转换为
    A_v2_transformed.xml
  • 我将
    A_v1_transformed.xml
    A_v2_transformed.xml
    进行比较,令我沮丧的是,它们并不完全相同。此外,它们都不符合
    expected.xml
    中所示的预期顺序。它们具有相同的内容,但元素的排序顺序不同
  • 我的第一个排序是
    。将我转到
    (与我正在使用的
    具有相同的效果)。当我将这两种排序组合使用时,我几乎得到了我想要的,但在某些地方,预期的字母顺序似乎只是随机打破的

    我已经增强了我的样本文件。为了简短起见,我只是把它们放在了pastebin上

    下面是我添加的带有注释的转换文件之一,以帮助您理解我认为转换对这些文件排序错误的位置/原因。我没有对另一个转换的文件进行注释,因为它有类似的“失败”

    两个转换后的文档应具有与
    expected.xml
    相同的校验和,但它们没有这是我最大的担忧。字母排序似乎是最合理的排序方式,但只要转换以某种合理的方式排序,我就不在乎排序是如何发生的只要排序可以在同一文件的不同“版本”之间重复。

    下面的XLS文件都会产生相同的结果,但“多通道”版本可能更容易理解

    讨论要点:

  • 我注意到,按字母大写排序时,字母优先。即使大写字母按字母顺序排在小写字母之后,也会排在第一位
  • 部分成功…

    我想我自己可能偶然发现了一个局部解决方案,但我不清楚为什么它会起作用。如果查看我的
    xsl\u multi\u pass.xsl
    文件,您将看到:

        <!-- Third pass with sortElements mode templates -->
        <xsl:variable name="sortElementsRslt">
            <xsl:apply-templates mode="sortElements" select="$sortAttributesRslt"/>
        </xsl:variable>
    
        <!-- Fourth pass with deDup mode templates -->
        <xsl:apply-templates mode="deDup" select="$sortElementsRslt"/>
    
    
    
    如果我把它变成:

        <!-- Third pass with sortElements mode templates -->
        <xsl:variable name="sortElementsRslt1">
            <xsl:apply-templates mode="sortElements" select="$sortAttributesRslt"/>
        </xsl:variable>
    
        <!-- Fourth pass with sortElements mode templates -->
        <xsl:variable name="sortElementsRslt2">
            <xsl:apply-templates mode="sortElements" select="$sortElementsRslt1"/>
        </xsl:variable>
    
        <!-- Fifth pass with deDup mode templates -->
        <xsl:apply-templates mode="deDup" select="$sortElementsRslt2"/>
    
    
    
    这会对元素进行两次排序,我不知道为什么有必要这样做。使用我提供的示例文件得到的结果是我所期望的减去优先使用的大写字母,但只要结果看起来是一致的,我就不会感到困扰。问题是这个“解决方案”导致我正在处理的真实文件的另一部分排序不一致


    成功

    我想我终于100%按我的意愿工作了。我通过元素的属性名和值将答案中给出的函数合并到元素中。由于某种原因,我仍然需要执行两次过程来对元素进行排序(应用完全相同的模板两次),正如我在上面所描述的,但是对于20MB的文件,这只需要额外的3秒钟,所以我不太担心

    以下是最终结果:

    简而言之,我所有XSLT问题的最终目标都是一个样式表,当应用到文件时,即使在该文件的不同“版本”上运行,也会始终生成相同的结果。文件的不同“版本”是指内容完全相同,只是顺序不同。这意味着元素的属性可能已被移动,并且元素可能比以前更早/更晚出现

    为此,您是否考虑过使用不同的工具而不是XSLT?你所描述的目标在我看来几乎完全是


    成功

    我想我终于100%按我的意愿工作了。我合并了答案中给出的函数,用于按属性名称和值对元素进行排序。由于某种原因,我仍然需要执行两次过程来对元素进行排序(应用完全相同的模板两次),正如我在上面所描述的,但是对于20MB的文件,这只需要额外的3秒钟,所以我不太担心

    以下是最终结果:


    这种转换是100%通用的,应该能够在任何XML文档中使用,将其按我认为最明智的方式排序。此样式表的主要优点是,它将以完全相同的方式以不同的顺序转换具有相同内容的多个文件,所有具有相同内容的文件的转换结果将是相同的。

    我正在寻找不同的工具,但我不知道XMLUnit。如果它可以根据我对相等性的描述区分两个文件,那么它现在就可以满足我的需要,但最终我需要一些东西,能够获取一个文件的各种“版本”,这些文件是相等的,但排序不同,并将这些版本中的每一个转换为规范化和排序的输出。文件的每个版本的规范化和排序输出都是二进制的,每个版本都有相同的校验和
    // control and test are the two XML documents you want to compare, they can
    // be String, Reader, org.w3c.dom.Document or org.xml.sax.InputSource
    Diff d = new Diff(control, test);
    assert d.similar();