需要根据记录 ID 合并来自两个 xml 个文件的数据

need to merge data from two xml files based on record id

我有以下两个 xml 文件。 文件 A:

<breakfast_menu>
    <food>
        <id>1</id>
        <name>Belgian Waffles</name>
        <price>.95</price>
        <calories>650</calories>
    </food>
    <food>
        <id>2</id>
        <name>Strawberry Belgian Waffles</name>
        <price>.95</price>
        <calories>900</calories>
    </food>
</breakfast_menu>

和文件 B:

<breakfast_menu>
    <food>
        <id>1</id>
        <description>here we have already a description element</description>
        <otherData>s3650</otherData>
    </food>
    <food>
        <id>2</id>
        <otherData>s3250</otherData>
        <otherData2>g508</otherData2>
        <otherData3>sidi6098</otherData3>
    </food>
</breakfast_menu>

我无法实现的是,对于每条根据记录 ID 匹配的记录,从名为 A 的 xml 文件中获取所有信息,并将所有这些信息放入文件 B 的描述元素中,但是也保留它来自的元素。如果匹配记录没有描述元素,我们添加一个。如果它已经有一个,那么我们必须知道从文件 A 中获取的信息从哪里开始,使用文本分隔符,即“-followingInfoTakenFromFileA-”。因此,考虑到上述情况,所需的输出应该是这样的:

 <breakfast_menu>
    <food>
        <id>1</id>
        <description>here we have already a description element-followingInfoTakenFromFileA-name:Belgian Waffles-price:.95-calories:650</description>
        <otherData>s3650</otherData>
    </food>
    <food>
        <id>2</id>
        <otherData>s3250</otherData>
        <otherData2>g508</otherData2>
        <otherData3>sidi6098</otherData3>
        <description>name:Strawberry Belgian Waffles-price:.95-calories:900</description>
    </food>
</breakfast_menu>

看来,考虑到已排序的 id 合并键,xsl:merge:

的简单任务
<xsl:stylesheet xmlns:xsl="http://www.w3.org/1999/XSL/Transform"
    xmlns:xs="http://www.w3.org/2001/XMLSchema"
    exclude-result-prefixes="#all"
    expand-text="yes"
    version="3.0">

  <xsl:param name="doc-A">
<breakfast_menu>
    <food>
        <id>1</id>
        <name>Belgian Waffles</name>
        <price>.95</price>
        <calories>650</calories>
    </food>
    <food>
        <id>2</id>
        <name>Strawberry Belgian Waffles</name>
        <price>.95</price>
        <calories>900</calories>
    </food>
</breakfast_menu>
  </xsl:param>

  <xsl:mode on-no-match="shallow-copy"/>

  <xsl:output method="xml" indent="yes"/>

  <xsl:template match="/*">
    <xsl:copy>
        <xsl:merge>
            <xsl:merge-source for-each-item="." select="food">
                <xsl:merge-key select="id"/>
            </xsl:merge-source>
            <xsl:merge-source for-each-item="$doc-A" select="//food">
                <xsl:merge-key select="id"/>
            </xsl:merge-source>
            <xsl:merge-action>
                <xsl:copy>
                    <xsl:apply-templates select="*">
                        <xsl:with-param name="merge-data" 
                          select="let $data := string-join(current-merge-group()[2]/(* except id)!(name() || ':' || .), '-')
                                  return if (description)
                                         then '-followingInfoTakenFrom' || document-uri(root(current-merge-group()[2])) || $data
                                         else $data"/>
                    </xsl:apply-templates>
                </xsl:copy>
            </xsl:merge-action>
        </xsl:merge>
    </xsl:copy>
  </xsl:template>

  <xsl:template match="food/description">
      <xsl:param name="merge-data"/>
      <xsl:copy>{.}{$merge-data}</xsl:copy>
  </xsl:template>

  <xsl:template match="food[not(description)]/*[last()]">
      <xsl:param name="merge-data"/>
      <xsl:next-match/>
      <description>{$merge-data}</description>
  </xsl:template>

</xsl:stylesheet>

https://xsltfiddle.liberty-development.net/pPzifqo

该示例将第一个文档内联为样本自包含的参数,但在现实世界中,您可以从 URL 加载,例如<xsl:param name="doc-A" select="doc('fileA.xml')"/>.