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

时间:2014-10-08 15:38:00

标签: xslt

我有两个相互关联的连续元素列表。我想把它们结合起来,但我的解决方案既慢又不优雅。我正在使用XSLT 2.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>

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>

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

预期结果(相同顺序:)

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

现在显而易见的方法就是通过一个列表然后选择 来自第二个的值。我是这样做的:

<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)与这个问题有关:在处理数十万件物品时,这个解决方案太慢了。什么是更好的解决方案?

2 个答案:

答案 0 :(得分:1)

如果我理解正确,您可以匹配公共值或位置。这里匹配价值:

XSLT 2.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>

此处匹配&#34;位置&#34;:

XSLT 2.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="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>

注意
正如我之前提到的,如果这不是你的最终结果,那么就没有必要构建它。正如你所看到的,&#34;其他&#34;值总是可以从List1的上下文中获得 - 您只需要在需要时指向它..

答案 1 :(得分:0)

这个问题已经解决了,但是为了防止任何人试图连接两个节点列表,我使用了这里的解决方案:Using xslt get node value at X position

<xsl:for-each select="items[not(@save)]/text">
    <xsl:variable name="pos" select="position()" />
    <option>
        <xsl:attribute name="value"><xsl:value-of select="../../items[@save]/text[position() = $pos]" /></xsl:attribute>
        <xsl:value-of select="."/>
    </option>
</xsl:for-each>

这允许我组合两组节点来创建带有值的HTML选项列表,使用XSLT 1.0。