英文:
Merging two XML files with XSLT 3.0
问题
我想要使用XSLT 3.0中引入的xsl:merge指令:
[https://www.w3.org/TR/xslt-30/#merging]
根据示例 '合并具有相同结构的多个文档',我可以在一个键上合并两个列表,但我在尝试在两个嵌套键上进行合并时遇到了问题。
以下是我的两个测试XML文件:
<list>
<item id="1">
<descr ref="a"/>
<descr ref="b"/>
</item>
<item id="2">
<descr ref="c"/>
<descr ref="d"/>
</item>
<item id="3">
<descr ref="e">one</descr>
<descr ref="f">one</descr>
</item>
</list>
和:
<list>
<item id="3">
<descr ref="e">two</descr>
<descr ref="f">two</descr>
<descr ref="x">two</descr>
</item>
<item id="4">
<descr ref="z"/>
<descr ref="y"/>
</item>
</list>
这是我的XSLT:
<xsl:stylesheet xmlns:xsl="http://www.w3.org/1999/XSL/Transform" xmlns:xs="http://www.w3.org/2001/XMLSchema" exclude-result-prefixes="xs" version="3.1">
<xsl:output method="xml" indent="yes" encoding="UTF-8"/>
<xsl:mode on-no-match="shallow-copy"/>
<xsl:template match="/">
<list>
<xsl:merge>
<xsl:merge-source name="master" for-each-source="'list1.xml'" sort-before-merge="yes" select="/list/item">
<xsl:merge-key select="@id" order="ascending"/>
</xsl:merge-source>
<xsl:merge-source name="update" for-each-source="'list2.xml'" sort-before-merge="yes" select="/list/item">
<xsl:merge-key select="@id" order="ascending"/>
</xsl:merge-source>
<xsl:merge-action>
<xsl:choose>
<xsl:when test="empty(current-merge-group('update'))">
<xsl:copy-of select="current-merge-group('master')"/>
<xsl:message>master!</xsl:message>
</xsl:when>
<xsl:when test="empty(current-merge-group('master'))">
<xsl:copy-of select="current-merge-group('update')"/>
<xsl:message>update!</xsl:message>
</xsl:when>
<xsl:otherwise>
<item>
<xsl:merge>
<xsl:merge-source name="descr-master" sort-before-merge="yes" select="descr">
<xsl:merge-key select="@ref" order="ascending"/>
</xsl:merge-source>
<xsl:merge-source name="descr-update" sort-before-merge="yes" select="descr">
<xsl:merge-key select="@ref" order="ascending"/>
</xsl:merge-source>
<xsl:merge-action>
<xsl:choose>
<xsl:when test="empty(current-merge-group('descr-update'))">
<xsl:copy-of select="current-merge-group('descr-master')"/>
<xsl:message>descr master!</xsl:message>
</xsl:when>
<xsl:when test="empty(current-merge-group('descr-master'))">
<xsl:copy-of select="current-merge-group('descr-update')"/>
<xsl:message>descr update!</xsl:message>
</xsl:when>
<xsl:otherwise>
<xsl:copy-of select="current-merge-group('descr-update')"/>
<xsl:message>present in both: kept update!</xsl:message>
</xsl:otherwise>
</xsl:choose>
</xsl:merge-action>
</xsl:merge>
</item>
</xsl:otherwise>
</xsl:choose>
</xsl:merge-action>
</xsl:merge>
</list>
</xsl:template>
</xsl:stylesheet>
当项目仅出现在两个列表中的一个时,结果是正确的,但不同时出现在两个列表中时存在问题。
有什么问题吗?
我尝试实现的目标是得到这个列表:
<list>
<item id="1">
<descr ref="a"/>
<descr ref="b"/>
</item>
<item id="2">
<descr ref="c"/>
<descr ref="d"/>
</item>
<item id="3">
<descr ref="e">two</descr>
<descr ref="f">two</descr>
<descr ref="x">two</descr>
</item>
<item id="4">
<descr ref="z"/>
<descr ref="y"/>
</item>
</list>
英文:
I would like to use the xsl:merge instruction introduced in XSLT 3.0:
[https://www.w3.org/TR/xslt-30/#merging]
Following the example 'Merging Several Documents with the Same Structure', I can merge two lists on one key, but I am having trouble trying to do so on two nested keys.
Here are my two test XML files:
<list>
<item id="1">
<descr ref="a"/>
<descr ref="b"/>
</item>
<item id="2">
<descr ref="c"/>
<descr ref="d"/>
</item>
<item id="3">
<descr ref="e">one</descr>
<descr ref="f">one</descr>
</item>
</list>
and:
<list>
<item id="3">
<descr ref="e">two</descr>
<descr ref="f">two</descr>
<descr ref="x">two</descr>
</item>
<item id="4">
<descr ref="z"/>
<descr ref="y"/>
</item>
</list>
And here is my XSLT:
<xsl:stylesheet xmlns:xsl="http://www.w3.org/1999/XSL/Transform" xmlns:xs="http://www.w3.org/2001/XMLSchema" exclude-result-prefixes="xs" version="3.1">
<xsl:output method="xml" indent="yes" encoding="UTF-8"/>
<xsl:mode on-no-match="shallow-copy"/>
<xsl:template match="/">
<list>
<xsl:merge>
<xsl:merge-source name="master" for-each-source="'list1.xml'" sort-before-merge="yes" select="/list/item">
<xsl:merge-key select="@id" order="ascending"/>
</xsl:merge-source>
<xsl:merge-source name="update" for-each-source="'list2.xml'" sort-before-merge="yes" select="/list/item">
<xsl:merge-key select="@id" order="ascending"/>
</xsl:merge-source>
<xsl:merge-action>
<xsl:choose>
<xsl:when test="empty(current-merge-group('update'))">
<xsl:copy-of select="current-merge-group('master')"/>
<xsl:message>master!</xsl:message>
</xsl:when>
<xsl:when test="empty(current-merge-group('master'))">
<xsl:copy-of select="current-merge-group('update')"/>
<xsl:message>update!</xsl:message>
</xsl:when>
<xsl:otherwise>
<item>
<xsl:merge>
<xsl:merge-source name="descr-master" sort-before-merge="yes" select="descr">
<xsl:merge-key select="@ref" order="ascending"/>
</xsl:merge-source>
<xsl:merge-source name="descr-update" sort-before-merge="yes" select="descr">
<xsl:merge-key select="@ref" order="ascending"/>
</xsl:merge-source>
<xsl:merge-action>
<xsl:choose>
<xsl:when test="empty(current-merge-group('descr-update'))">
<xsl:copy-of select="current-merge-group('descr-master')"/>
<xsl:message>descr master!</xsl:message>
</xsl:when>
<xsl:when test="empty(current-merge-group('descr-master'))">
<xsl:copy-of select="current-merge-group('descr-update')"/>
<xsl:message>descr update!</xsl:message>
</xsl:when>
<xsl:otherwise>
<xsl:copy-of select="current-merge-group('descr-update')"/>
<xsl:message>present in both: kept update!</xsl:message>
</xsl:otherwise>
</xsl:choose>
</xsl:merge-action>
</xsl:merge>
</item>
</xsl:otherwise>
</xsl:choose>
</xsl:merge-action>
</xsl:merge>
</list>
</xsl:template>
</xsl:stylesheet>
The result is correct when an item is present in just one of the two lists, but not in both.
What's wrong?
What I am trying to achieve would be this list:
<list>
<item id="1">
<descr ref="a"/>
<descr ref="b"/>
</item>
<item id="2">
<descr ref="c"/>
<descr ref="d"/>
</item>
<item id="3">
<descr ref="e">two</descr>
<descr ref="f">two</descr>
<descr ref="x">two</descr>
</item>
<item id="4">
<descr ref="z"/>
<descr ref="y"/>
</item>
</list>
答案1
得分: 1
你需要从外部合并组中提取数据:
<xsl:otherwise>
<item>
<xsl:merge>
<xsl:merge-source name="descr-master" sort-before-merge="yes" select="current-merge-group('master')/descr">
<xsl:merge-key select="@ref" order="ascending"/>
</xsl:merge-source>
<xsl:merge-source name="descr-update" sort-before-merge="yes" select="current-merge-group('update')/descr">
<xsl:merge-key select="@ref" order="ascending"/>
</xsl:merge-source>
<xsl:merge-action>
<xsl:choose>
<xsl:when test="empty(current-merge-group('descr-update'))">
<xsl:copy-of select="current-merge-group('descr-master')"/>
<xsl:message>descr master!</xsl:message>
</xsl:when>
<xsl:when test="empty(current-merge-group('descr-master'))">
<xsl:copy-of select="current-merge-group('descr-update')"/>
<xsl:message>descr update!</xsl:message>
</xsl:when>
<xsl:otherwise>
<xsl:copy-of select="current-merge-group('descr-update')"/>
<xsl:message>present in both: kept update!</xsl:message>
</xsl:otherwise>
</xsl:choose>
</xsl:merge-action>
</xsl:merge>
</item>
</xsl:otherwise>
(Note: This is the translation of the provided XML code.)
英文:
You need to pick up the data from the outer merge groups:
<xsl:otherwise>
<item>
<xsl:merge>
<xsl:merge-source name="descr-master" sort-before-merge="yes" select="current-merge-group('master')/descr">
<xsl:merge-key select="@ref" order="ascending"/>
</xsl:merge-source>
<xsl:merge-source name="descr-update" sort-before-merge="yes" select="current-merge-group('update')/descr">
<xsl:merge-key select="@ref" order="ascending"/>
</xsl:merge-source>
<xsl:merge-action>
<xsl:choose>
<xsl:when test="empty(current-merge-group('descr-update'))">
<xsl:copy-of select="current-merge-group('descr-master')"/>
<xsl:message>descr master!</xsl:message>
</xsl:when>
<xsl:when test="empty(current-merge-group('descr-master'))">
<xsl:copy-of select="current-merge-group('descr-update')"/>
<xsl:message>descr update!</xsl:message>
</xsl:when>
<xsl:otherwise>
<xsl:copy-of select="current-merge-group('descr-update')"/>
<xsl:message>present in both: kept update!</xsl:message>
</xsl:otherwise>
</xsl:choose>
</xsl:merge-action>
</xsl:merge>
</item>
</xsl:otherwise>
答案2
得分: 0
它有效!只需完成解决方案,以便复制 @id/item,这部分遗漏了:
<xsl:copy>
<xsl:apply-templates select="@*"/>
<xsl:merge>
非常感谢!
英文:
It works!
Just to complete the solution, in order to copy the @id/item, this was missing:
<xsl:copy>
<xsl:apply-templates select="@*"/>
<xsl:merge>
Thanks a lot!
通过集体智慧和协作来改善编程学习和解决问题的方式。致力于成为全球开发者共同参与的知识库,让每个人都能够通过互相帮助和分享经验来进步。
评论