使用 XSLT 基于 ID 从多个 xPath 中选择 XML 节点

Posted

技术标签:

【中文标题】使用 XSLT 基于 ID 从多个 xPath 中选择 XML 节点【英文标题】:Select XML Node from multiple xPath based on ID using XSLT 【发布时间】:2022-01-04 07:08:00 【问题描述】:

我目前正在处理一项任务,我需要遍历 XML 文件的两个不同部分(两个文件之前合并到这个文件中)并搜索 ID。

如果文件的两个位置的 ID、颜色和数量值都匹配,我需要选择第二个文件 (fileB) 中的所有字段。

如果没有,那么我需要从第一个文件 (fileA) 中选择字段。

这是一个 XML 示例:

<root>
  <fileA>
    <data>
        <id>123</id>
        <color>Green</color>
        <quantaties>5</quantaties>
    </data>
    <data>
        <id>456</id>
        <color>Red</color>
        <quantaties>7</quantaties>
    </data>
    <data>
        <id>789</id>
        <color>Blue</color>
        <quantaties>9</quantaties>
    </data>
  </fileA>
  <fileB>
    <data>
        <id>456</id>
        <color>Red</color>
        <quantaties>7</quantaties>
        <date>15-07-2021</date>
        <reason>Internal</reason>
    </data>
  </fileB>
</root>

在上面的示例中,两个文件中都只有 id 456,颜色为红色,数量为 7。在这种情况下,我想从 fileB 填充那个。所以我想要的输出是:

<root>
  <newFile>
    <data>
        <id>123</id>
        <color>Green</color>
        <quantaties>5</quantaties>
    </data>
    <data>
        <id>456</id>
        <color>Red</color>
        <quantaties>7</quantaties>
        <date>15-07-2021</date>
        <reason>Internal</reason>
    </data>
    <data>
        <id>789</id>
        <color>Blue</color>
        <quantaties>9</quantaties>
    </data>
  </newFile>
</root>

请记住,多个字段必须匹配,而不仅仅是 ID。还有颜色和数量,以便选择 fileB 数据。谁能帮我解决这个问题?挣扎了一段时间。

【问题讨论】:

“多个字段必须匹配” 我们是否事先知道这些字段的名称(如您的示例中的 ID、颜色和数量)? 是的。它始终是 ID、颜色和数量字段。它们的名称总是相同的。 【参考方案1】:

我会这样做:

XSLT 3.0

<xsl:stylesheet version="3.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="fileB" match="fileB/data" use="id||color||quantaties"/>

<xsl:template match="/root">
    <xsl:copy>
        <newFile>
            <xsl:for-each select="fileA/data">
                <xsl:copy>
                    <xsl:copy-of select="*, key('fileB', id||color||quantaties)/(* except (id|color|quantaties))"/>
                </xsl:copy>
            </xsl:for-each>
        </newFile>
    </xsl:copy>
</xsl:template>

</xsl:stylesheet>

请注意,这假定 color 不以数字开头或结尾 - 否则您应该在 key 值中插入分隔符。


或者你可以这样做:

<xsl:stylesheet version="3.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="/root">
    <xsl:copy>
        <newFile>
            <xsl:for-each-group select="*/data" group-by="id, color, quantaties" composite="yes">
                <xsl:copy>
                    <xsl:for-each-group select="current-group()/*" group-by="name()" >
                        <xsl:copy-of select="."/>
                    </xsl:for-each-group>
                </xsl:copy>
            </xsl:for-each-group>
        </newFile>
    </xsl:copy>
</xsl:template>

</xsl:stylesheet>

【讨论】:

谢谢迈克尔。这是一些惊人的例子,正是我想要的。

以上是关于使用 XSLT 基于 ID 从多个 xPath 中选择 XML 节点的主要内容,如果未能解决你的问题,请参考以下文章

使用带有多个表达式的祖先或自我选择 text() XSLT XPATH

在 XSLT 中,如何使用存在多个相同节点的 ID 从节点中选择一个值?

支持 XPath 2.0 的 Java XSLT 处理器

XSLT XPATH 出错(表达式必须计算为节点集)

如何在 xslt 上使用 ID/IDref 连接内容?

XSLT:测试当前元素是不是匹配变量 xpath