需要根据记录 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')"/>
.
我有以下两个 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')"/>
.