xslt-3.0 - 需要根据记录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>
解决方案
看起来,给定排序的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')"/>
。
推荐阅读
- symfony - Symfony @Assert\Type("string") 验证通过整数值
- junit - 已检查的异常对此方法无效!Junit5 JMSException 测试失败
- css - 有没有更好的方法将此背景图像与其上方的文本对齐?
- python - 将json文件转换为toml文件
- python - 在重定向烧瓶中传递数组/列表作为参数
- ios - 将用户输入的信息传递给 View 并用它创建一个新的类似小部件的卡片
- firebase - 带有 Okta 身份提供程序 (IdP) 的 Google Cloud Storage
- python - 用循环替换字符串中的单词
- python - 根据条件创建新列会出错
- asp.net-core - Blazor 中的项目,控制器无法正常工作并且程序文件错误很多