如何创建 XSLT 以根据两个 XML 文档之间的兄弟节点文本匹配来合并这两个文档?

How do I create an XSLT to merge two XML documents based on a sibling node text matching between the two?

我正在寻求有关以下问题的帮助。我正在尝试创建一个 XSLT,它最终将合并 Main.xml 和 Main_2.xml 之间的内容。这些是人为的例子,但结构是正确的。目标只是将 Main.xml 中的任何 'fff' 和 'zzz' 元素替换为 'ggg' 元素及其来自 Main_2.xml 的子元素(如果它们的 'ccc' 兄弟姐妹匹配)在 Main.xml 和 Main_2.xml 中。 Main.xml 的其余部分必须保持不变。任何指针或参考表示赞赏。

Main.xml

<aaa>
    <bbb>
        <ccc>1234</ccc>
        <ddd>apple</ddd>
        <eeee>oranges</eeee>
        <fff>bananas</fff>
    </bbb>
    <bbb>
        <ccc>9876</ccc>
        <ddd>pears</ddd>
        <eeee>watermelon</eeee>
        <zzz>grapes</zzz>
    </bbb>
</aaa>

Main_2.xml

<aaa>
    <bbb>
        <ccc>1234</ccc>
        <ddd>apple</ddd>
        <eeee>oranges</eeee>
        <ggg>
            <hhh>asdf</hhh>
            <iii>
                <jjj>blue</jjj>
                <kkk>red</kkk>
                <lll>green</lll>
            </iii>
        </ggg>
    </bbb>
    <bbb>
        <ccc>9876</ccc>
        <ddd>pears</ddd>
        <eeee>watermelon</eeee>
        <ggg>
            <hhh>fdsa</hhh>
            <iii>
                <jjj>purple</jjj>
                <kkk>yellow</kkk>
                <lll>white</lll>
            </iii>
        </ggg>
    </bbb>
    <bbb>
        <ccc>45678</ccc>
        <ddd>veggies</ddd>
        <eeee>carrots</eeee>
        <ggg>
            <hhh>zxcf</hhh>
            <iii>
                <jjj>cyan</jjj>
                <kkk>black</kkk>
            </iii>
        </ggg>
    </bbb>
</aaa>

期望的输出

<aaa>
    <bbb>
        <ccc>1234</ccc>
        <ddd>apple</ddd>
        <eeee>oranges</eeee>
        <ggg>
            <hhh>asdf</hhh>
            <iii>
                <jjj>blue</jjj>
                <kkk>red</kkk>
                <lll>green</lll>
            </iii>
        </ggg>
    </bbb>
    <bbb>
        <ccc>9876</ccc>
        <ddd>pears</ddd>
        <eeee>watermelon</eeee>
        <ggg>
            <hhh>fdsa</hhh>
            <iii>
                <jjj>purple</jjj>
                <kkk>yellow</kkk>
                <lll>white</lll>
            </iii>
        </ggg>
    </bbb>
</aaa>

当前的 XSLT

<?xml version="1.0" encoding="UTF-8"?>
<xsl:stylesheet version="1.0"
  xmlns:xsl="http://www.w3.org/1999/XSL/Transform"
  xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance">

    <xsl:output method="xml" indent="yes" version="1.0" encoding="utf-8" />

    <xsl:variable name="tempMain" select="document('Main_2.xml')"/>

<!-- attempt at using key, didn't pan out
    <xsl:key name="fruits" match="bbb" use="ccc"/>
-->

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


    <!-- Replace these fields with new ones -->
    <xsl:template match="fff | zzz">
        <xsl:copy-of select="$tempMain/aaa/bbb[ccc = current()../ccc]/ggg"/>

    </xsl:template>  -->

</xsl:stylesheet>

作为一个不完全相关的附带问题,您在创建 XSLT 时会推荐哪些资源?我已经完成了关于 w3schools 的教程,这不是最好的。我觉得我只是在复制不同问题的点点滴滴,看看有什么用,但宁愿提高我的知识。

编辑 michael.hor257k 的答案有效,我只需要修改它,以便在 Main_2.xml

中找不到 ccc 文本时它不会删除 fff 或 zzz 元素

这样试试?

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:strip-space elements="*"/>

<xsl:param name="path-to-lookup"> Main_2.xml</xsl:param>
<xsl:key name="fruits" match="bbb" use="ccc"/>

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

<xsl:template match="fff | zzz">
    <xsl:variable name="key" select="../ccc"/>
    <!-- switch context to use key -->
    <xsl:for-each select="document($path-to-lookup)">
        <xsl:apply-templates select="key('fruits', $key)/ggg"/>
    </xsl:for-each>
</xsl:template>

</xsl:stylesheet>

已添加:

how could I modify it to not delete fff or zzz elements if the text from ccc in Main.xml doesn't match a ccc element from Main_2.xml?

在这种情况下,我可能会放弃使用密钥,并执行:

<xsl:template match="fff | zzz">
    <xsl:variable name="lookup" select="document($path-to-lookup)/aaa/bbb[ccc=current()/../ccc]"/>
    <xsl:choose>
        <xsl:when test="$lookup">
            <xsl:copy-of select="$lookup/ggg"/>
        </xsl:when>
        <xsl:otherwise>
            <xsl:copy-of select="."/>
        </xsl:otherwise>
    </xsl:choose>
</xsl:template>