【问题标题】:How to copy values by matching nodes in XSLT如何通过匹配 XSLT 中的节点来复制值
【发布时间】:2019-07-04 01:37:50
【问题描述】:

在我的 XML 中,如果两个节点在其他一些节点中具有匹配的值,我想将值从另一个节点复制到一个节点中。

<XML>
    <ORG>
        <ITM>
            <NUM>1</NUM>
            <SEQ>10</SEQ>
            <VAL>X</VAL>
        </ITM>
        <ITM>
            <NUM>2</NUM>
            <SEQ>20</SEQ>
            <VAL>Y</VAL>
        </ITM>
    </ORG>
    <NEW>
        <ITM>
            <NUM>1</NUM>
            <SEQ>10</SEQ>
            <VAL>QQQ</VAL>
        </ITM>
    </NEW>
</XML>

这可行,但是对于大型文档可能会很慢,有没有更好的方法?

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

    <xsl:template match="@*|node()">
        <xsl:copy>
            <xsl:apply-templates select="@*|node()"/>
        </xsl:copy>
    </xsl:template>


    <xsl:template match="ORG/ITM/VAL">
        <xsl:variable name="NUM" select="../NUM"/>
        <xsl:variable name="SEQ" select="../SEQ"/>
        <VAL>
            <xsl:value-of select="../../../NEW/ITM/VAL[../NUM=$NUM and ../SEQ=$SEQ]"/>
        </VAL>
    </xsl:template>
</xsl:stylesheet>

由于 ORG/ITM/NUM 和 ORD/ITM/SEQ 与 NEW/ITM/NUM 和 NEW/ITM/SEQ 匹配,结果在 ORG/ITM/VAL 节点中的值为“QQQ”

<?xml version="1.0"?>
<XML>
    <ORG>
        <ITM>
            <NUM>1</NUM>
            <SEQ>10</SEQ>
            <VAL>QQQ</VAL>
        </ITM>
        <ITM>
            <NUM>2</NUM>
            <SEQ>20</SEQ>
            <VAL/>
        </ITM>
    </ORG>
    <NEW>
        <ITM>
            <NUM>1</NUM>
            <SEQ>10</SEQ>
            <VAL>QQQ</VAL>
        </ITM>
    </NEW>
</XML>

【问题讨论】:

    标签: xslt copy matching


    【解决方案1】:

    查找值的首选方法是定义一个 key 并使用它。在给定的示例中,这可能是:

    XSLT 1.0

    <xsl:stylesheet version="1.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="new-item" match="NEW/ITM" use="concat(NUM, '|', SEQ)" />
    
    <!-- identity transform -->
    <xsl:template match="@*|node()">
        <xsl:copy>
            <xsl:apply-templates select="@*|node()"/>
        </xsl:copy>
    </xsl:template>
    
    <xsl:template match="ORG/ITM/VAL">
        <xsl:copy>
             <xsl:value-of select="key('new-item', concat(../NUM, '|', ../SEQ))/VAL"/>
        </xsl:copy>
    </xsl:template>
    
    </xsl:stylesheet>
    

    【讨论】:

    • 感谢您的帮助!那就是我一直在寻找的。​​span>
    【解决方案2】:

    使用 1 个变量更快。

    <xsl:stylesheet version="1.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform">
        <xsl:output method="xml" version="1.0" encoding="UTF-8" indent="yes"/>
    
        <xsl:template match="@*|node()">
            <xsl:copy>
                <xsl:apply-templates select="@*|node()"/>
            </xsl:copy>
        </xsl:template>
    
    
        <xsl:template match="ORG/ITM/VAL">
            <xsl:variable name="NUMSEQ" select="concat(string(../NUM), string(../SEQ))"/>        
            <VAL>
                <xsl:value-of select="../../../NEW/ITM/VAL[concat(string(../NUM), string(../SEQ))=$NUMSEQ]"/>
            </VAL>
        </xsl:template>
    </xsl:stylesheet>
    

    【讨论】:

    • 您的方法无法区分&lt;NUM&gt;1&lt;/NUM&gt;&lt;SEQ&gt;23&lt;/SEQ&gt; 和&lt;NUM&gt;12&lt;/NUM&gt;&lt;SEQ&gt;3&lt;/SEQ&gt;。无论如何,使用 key 会更有效。
    • 感谢您的评论。使用 concat(string(../NUM),'~', string(../SEQ)) 如果 NUM 和 SEQ 是数字,我们可以使键唯一。
    • string() 函数在这里没有完成任何事情。
    猜你喜欢
    • 2015-01-07
    • 2010-12-01
    • 1970-01-01
    • 2021-03-21
    • 1970-01-01
    • 2019-10-08
    • 2018-04-18
    • 2017-01-13
    • 1970-01-01
    相关资源
    最近更新 更多