如何创建 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>
我正在寻求有关以下问题的帮助。我正在尝试创建一个 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>