更好的解决方案:使用XSLT按元素的位置组合两个大列表

更好的解决方案:使用XSLT按元素的位置组合两个大列表,xslt,Xslt,我有两个相互关联的连续元素列表。我想把它们结合起来,但我的解决方案既慢又不优雅。我使用的是XSLT2.0,Saxon List1.xml: <data> <w tag="a">asda</w> <w tag="c">sdsd</w> <w tag="a">value2</w> <w tag="f">fdxcc</w> <w tag="c">no</w> </d

我有两个相互关联的连续元素列表。我想把它们结合起来,但我的解决方案既慢又不优雅。我使用的是XSLT2.0,Saxon

List1.xml:

<data>
<w tag="a">asda</w>
<w tag="c">sdsd</w>
<w tag="a">value2</w>
<w tag="f">fdxcc</w>
<w tag="c">no</w>
</data>

阿斯达
sdsd
价值2
fdxcc
不
List2.xml:

<data>
<w class="2">asda</w>
<w class="5">sdsd</w>
<w class="6">value2</w>
<w class="1">fdxcc</w>
<w class="2">no</w>
</data>

阿斯达
sdsd
价值2
fdxcc
不
请注意,@class、@tag或元素内容的值都不是唯一的;链接它们的是相同的内容和相同的顺序。(请注意,实际问题更复杂,因为我需要使用第二个列表的元素来评估第一个列表的元素。)

预期结果(相同顺序:)

asda
sdsd
价值2
fdxcc
不
现在最明显的方法就是浏览一个列表,然后选择 第二个变量的值。我是这样做的:

<xsl:template match="/">
<xsl:variable name="list1" select="doc('list1.xml')">
<xsl:variable name="list2" select="doc(*list2.xml')">

<xsl:for-each select="$list1//w">
<xsl:copy>
<xsl:copy-of select="@tag"/>
<xsl:variable name="thispos" select="position()"/>
<xsl:copy-of select="$list2//w[position()=$thispos]/@id"/>
<xsl:copy-of select="@text()"/>
</xsl:copy>
</xsl:for-each>

我有两个问题: (a) 在$list1中引用位置真的没有比将其保存在变量中更好的方法了吗?
(b) 与此问题相关:此解决方案在处理数十万项时速度太慢。什么是更好的解决方案?

如果我理解正确,您可以在公共值或位置上进行匹配。以下是价值匹配:

XSLT2.0

<xsl:stylesheet version="2.0" 
xmlns:xsl="http://www.w3.org/1999/XSL/Transform">
<xsl:output method="xml" version="1.0" encoding="UTF-8" indent="yes"/>

<xsl:key name="list2" match="w" use="." />

<xsl:template match="/">
    <root>
        <xsl:for-each select="data/w">
            <xsl:copy>
                <xsl:copy-of select="@*"/>
                <xsl:copy-of select="key('list2', ., document('List2.xml'))/@*"/>
                <xsl:value-of select="."/>
            </xsl:copy>
        </xsl:for-each>
    </root>
</xsl:template>

</xsl:stylesheet>
<xsl:stylesheet version="2.0" 
xmlns:xsl="http://www.w3.org/1999/XSL/Transform">
<xsl:output method="xml" version="1.0" encoding="UTF-8" indent="yes"/>

<xsl:key name="list2" match="w" use="count(preceding-sibling::w)" />

<xsl:template match="/">
    <root>
        <xsl:for-each select="data/w">
            <xsl:copy>
                <xsl:copy-of select="@*"/>
                <xsl:copy-of select="key('list2', count(preceding-sibling::w), document('List2.xml'))/@*"/>
                <xsl:value-of select="."/>
            </xsl:copy>
        </xsl:for-each>
    </root>
</xsl:template>

</xsl:stylesheet>

下面是“位置”的匹配:

XSLT2.0

<xsl:stylesheet version="2.0" 
xmlns:xsl="http://www.w3.org/1999/XSL/Transform">
<xsl:output method="xml" version="1.0" encoding="UTF-8" indent="yes"/>

<xsl:key name="list2" match="w" use="." />

<xsl:template match="/">
    <root>
        <xsl:for-each select="data/w">
            <xsl:copy>
                <xsl:copy-of select="@*"/>
                <xsl:copy-of select="key('list2', ., document('List2.xml'))/@*"/>
                <xsl:value-of select="."/>
            </xsl:copy>
        </xsl:for-each>
    </root>
</xsl:template>

</xsl:stylesheet>
<xsl:stylesheet version="2.0" 
xmlns:xsl="http://www.w3.org/1999/XSL/Transform">
<xsl:output method="xml" version="1.0" encoding="UTF-8" indent="yes"/>

<xsl:key name="list2" match="w" use="count(preceding-sibling::w)" />

<xsl:template match="/">
    <root>
        <xsl:for-each select="data/w">
            <xsl:copy>
                <xsl:copy-of select="@*"/>
                <xsl:copy-of select="key('list2', count(preceding-sibling::w), document('List2.xml'))/@*"/>
                <xsl:value-of select="."/>
            </xsl:copy>
        </xsl:for-each>
    </root>
</xsl:template>

</xsl:stylesheet>

在这两种情况下,结果是:

<?xml version="1.0" encoding="UTF-8"?>
<root>
   <w tag="a" class="2">asda</w>
   <w tag="c" class="5">sdsd</w>
   <w tag="a" class="6">value2</w>
   <w tag="f" class="1">fdxcc</w>
   <w tag="c" class="2">no</w>
</root>

阿斯达
sdsd
价值2
fdxcc
不
注意

正如我前面提到的,如果这不是您的最终结果,那么就没有必要构建它。如您所见,“其他”值始终可以从列表1的上下文中使用-您只需要在需要时指向它。

问题早已解决,但为了防止它帮助任何人尝试连接两个节点列表,我在这里使用了一个解决方案:



这使我能够使用XSLT1.0将两组节点组合起来,创建一个带有值的HTML选项列表。

1。这些列表真的像示例中那样硬编码在样式表中吗?2.当您可以通过使用键直接(有效地)引用“其他”元素时,我不知道您为什么需要(组合)结果请说明您使用的XSLT版本。1。不,它们不是硬编码的,而是从大文件读入变量。这只是一个简单的例子。2.我想知道钥匙是否是实现这一点的方法,但也许我误解了你。我需要将结果写入文件,没有动态元素。最终,这将转到一个文本文件。我正在使用XSLT2.0。使用SSaxon.re 1:请相应地调整您的示例,因为它会产生很大的不同。re 2:key是执行查找的XSLT机制。我不知道你所说的“动态元素”是什么意思。最终,XSLT会生成一个输出树,可以(而且通常是)将其写入文件。Re 2:正如我所说,我期望XSLT键发挥作用,但我不明白这是如何工作的——阅读Kay的XSLT书籍就不知道了,这是我通常需要使用的全部内容。但我只是想你也可以指XML文件之间的一些动态链接。正如我所说,我不知道如何使用钥匙来完成这件事。如果你能澄清一下就好了。我很惊讶这个版本效率如此之低——我认为连续的职位申请可以优化。我的意思是:你能显示原始文件(或者有两个文件)吗?当然,最少但完整的示例是首选的。是的,这很有效!我以前不懂钥匙;现在我做到了,这无疑加快了速度。这引出了一个后续问题。我对它进行了测试,在xpath键函数中使用position()而不是count(前面的同级::w)要快得多。有没有办法在上面的定义中使用position()函数?这将大大加快速度。在调用key()函数时,您可能可以使用
position()-1
。我说可能,因为position()是上下文相关的。同一节点在不同上下文中将具有不同的位置。不能在xsl:key元素中使用position(),因为键没有上下文。是的,position()-1在key()函数中按预期工作,但它不能在xsl:element中使用这一事实仍然意味着构建索引的数量是w项的指数;换句话说,仍然相当缓慢。“我会试着想出另一个解决办法。@RuprechtvonWaldenfels IMHO,问题的真正解决办法就在你的上游:告诉准备输入的人为项目编制索引。您可以先自己转换几个文档来测试这个命题,然后在匹配公共id值时运行“真实”代码。当然,这会有所帮助,但这会改变情况,而不是解决问题,这对我来说更重要。解决方案是自己为输入文件编制索引,然后使用键获取这些索引。在使用数十万条目的生产示例中,这很好。我对解决方案进行了编辑,以反映这种方法。