首页 > 解决方案 > 需要根据记录id合并两个xml文件中的数据

问题描述

我有以下两个 xml 文件。档案一:

<breakfast_menu>
    <food>
        <id>1</id>
        <name>Belgian Waffles</name>
        <price>$5.95</price>
        <calories>650</calories>
    </food>
    <food>
        <id>2</id>
        <name>Strawberry Belgian Waffles</name>
        <price>$7.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:$5.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:$7.95-calories:900</description>
    </food>
</breakfast_menu>

标签: xslt-3.0

解决方案


看起来,给定排序的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>$5.95</price>
        <calories>650</calories>
    </food>
    <food>
        <id>2</id>
        <name>Strawberry Belgian Waffles</name>
        <price>$7.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')"/>


推荐阅读