0

我的 XSLT 传奇中的这一章是这里问题的扩展。感谢所有帮助我走到这一步的人(@Martin Honnen、@Ian Roberts、@Tim C 以及我想念的任何其他人)!

这是我目前的问题:

  1. 我将一些兄弟姐妹重新排序A_v1.xml以创建A_v2.xml. 我现在认为这两个文件是同一文件的不同“版本”。 文件 两个文件具有完全相同的内容,只是一些同级文件的顺序不同。换一种说法,in 中的每个元素A_v2.xml仍然具有与 in 相同的父元素A_v1.xml,但它现在可能出现在它曾经出现在其之后的兄弟姐妹之前,或者可能出现在它以前出现的兄弟姐妹之后。
  2. A_v1.xml我变身A_v1_transformed.xml
  3. A_v2.xml我变身A_v2_transformed.xml
  4. 我比较和令我沮丧的是A_v1_transformed.xmlA_v2_transformed.xml它们并不相同。此外,它们都不是图中所示的预期顺序expected.xml。它们具有相同的内容,但元素的排序顺序不同。

我的第一类是<xsl:sort select="local-name()"/>. @G。肯·霍尔曼(Ken Holman)把我变成了<xsl:sort select="."/>(这与我使用的效果相同<xsl:sort select="self::*"/>)。当我结合使用这两种类型时,我几乎得到了我想要的东西,但在某些地方,预期的字母顺序似乎只是随机破坏。

我已经加强了我的示例文件。为了使问题简短,我只是将它们放在pastebin上。

A_v1.xml

A_v2.xml

A_v1_transformed.xml

A_v2_transformed.xml

这是我添加的带有注释的转换文件之一,可帮助您了解我认为转换对这些文件进行错误排序的位置/原因。我没有评论其他转换后的文件,因为它有类似的“失败”。

A_v1_transformed_with_comments.xml

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

预期的.xml

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

xsl_concise.xsl

xsl_multi_pass.xsl

讨论要点:

  1. 我注意到,按字母顺序排序时,大写字母优先。即使大写字母按字母顺序排在小写字母之后,它也会排在第一位。

部分成功...

我想我自己可能偶然发现了一个部分解决方案,但我不清楚它为什么会起作用。如果您查看我的xsl_multi_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% 的工作。我通过属性名称和值将@Dimitre Novatchev在此处的答案中给出的函数合并到元素中。由于某种原因,我仍然需要执行两次传递来对元素进行排序(两次应用完全相同的模板),但是对于 20MB 的文件只需要额外的 3 秒,所以我不太担心。

这是最终结果:

xsl_2.0_full_document_sorter.xsl

4

2 回答 2

1

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

为此,您是否考虑过使用不同的工具而不是 XSLT?您描述的目标在我看来与 XMLUnit 中的similar()定义几乎完全相同

// 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();
于 2013-09-20T10:44:28.447 回答
0

成功!

我想我终于得到了我想要的 100% 的工作。我合并了@Dimitre Novatchev在此处的答案中给出的函数,以按元素的属性名称和值对元素进行排序。由于某种原因,我仍然需要执行两次传递来对元素进行排序(两次应用完全相同的模板),但是对于 20MB 的文件只需要额外的 3 秒,所以我不太担心。

这是最终结果:

xsl_2.0_full_document_sorter.xsl

这种转换是 100% 通用的,应该能够用于任何 XML 文档,以便以我认为最合理的方式对其进行排序。此样式表的主要好处是,它将以完全相同的方式将具有相同内容的多个文件以不同的顺序转换为具有相同内容的所有文件的转换结果将是相同的。

于 2013-09-23T17:23:44.840 回答