合并两个XML文件使用XSLT 3.0

huangapple go评论151阅读模式
英文:

Merging two XML files with XSLT 3.0

问题

我想要使用XSLT 3.0中引入的xsl:merge指令:
[https://www.w3.org/TR/xslt-30/#merging]

根据示例 '合并具有相同结构的多个文档',我可以在一个键上合并两个列表,但我在尝试在两个嵌套键上进行合并时遇到了问题。

以下是我的两个测试XML文件:

  1. <list>
  2. <item id="1">
  3. <descr ref="a"/>
  4. <descr ref="b"/>
  5. </item>
  6. <item id="2">
  7. <descr ref="c"/>
  8. <descr ref="d"/>
  9. </item>
  10. <item id="3">
  11. <descr ref="e">one</descr>
  12. <descr ref="f">one</descr>
  13. </item>
  14. </list>

和:

  1. <list>
  2. <item id="3">
  3. <descr ref="e">two</descr>
  4. <descr ref="f">two</descr>
  5. <descr ref="x">two</descr>
  6. </item>
  7. <item id="4">
  8. <descr ref="z"/>
  9. <descr ref="y"/>
  10. </item>
  11. </list>

这是我的XSLT:

  1. <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">
  2. <xsl:output method="xml" indent="yes" encoding="UTF-8"/>
  3. <xsl:mode on-no-match="shallow-copy"/>
  4. <xsl:template match="/">
  5. <list>
  6. <xsl:merge>
  7. <xsl:merge-source name="master" for-each-source="'list1.xml'" sort-before-merge="yes" select="/list/item">
  8. <xsl:merge-key select="@id" order="ascending"/>
  9. </xsl:merge-source>
  10. <xsl:merge-source name="update" for-each-source="'list2.xml'" sort-before-merge="yes" select="/list/item">
  11. <xsl:merge-key select="@id" order="ascending"/>
  12. </xsl:merge-source>
  13. <xsl:merge-action>
  14. <xsl:choose>
  15. <xsl:when test="empty(current-merge-group('update'))">
  16. <xsl:copy-of select="current-merge-group('master')"/>
  17. <xsl:message>master!</xsl:message>
  18. </xsl:when>
  19. <xsl:when test="empty(current-merge-group('master'))">
  20. <xsl:copy-of select="current-merge-group('update')"/>
  21. <xsl:message>update!</xsl:message>
  22. </xsl:when>
  23. <xsl:otherwise>
  24. <item>
  25. <xsl:merge>
  26. <xsl:merge-source name="descr-master" sort-before-merge="yes" select="descr">
  27. <xsl:merge-key select="@ref" order="ascending"/>
  28. </xsl:merge-source>
  29. <xsl:merge-source name="descr-update" sort-before-merge="yes" select="descr">
  30. <xsl:merge-key select="@ref" order="ascending"/>
  31. </xsl:merge-source>
  32. <xsl:merge-action>
  33. <xsl:choose>
  34. <xsl:when test="empty(current-merge-group('descr-update'))">
  35. <xsl:copy-of select="current-merge-group('descr-master')"/>
  36. <xsl:message>descr master!</xsl:message>
  37. </xsl:when>
  38. <xsl:when test="empty(current-merge-group('descr-master'))">
  39. <xsl:copy-of select="current-merge-group('descr-update')"/>
  40. <xsl:message>descr update!</xsl:message>
  41. </xsl:when>
  42. <xsl:otherwise>
  43. <xsl:copy-of select="current-merge-group('descr-update')"/>
  44. <xsl:message>present in both: kept update!</xsl:message>
  45. </xsl:otherwise>
  46. </xsl:choose>
  47. </xsl:merge-action>
  48. </xsl:merge>
  49. </item>
  50. </xsl:otherwise>
  51. </xsl:choose>
  52. </xsl:merge-action>
  53. </xsl:merge>
  54. </list>
  55. </xsl:template>
  56. </xsl:stylesheet>

当项目仅出现在两个列表中的一个时,结果是正确的,但不同时出现在两个列表中时存在问题。
有什么问题吗?

我尝试实现的目标是得到这个列表:

  1. <list>
  2. <item id="1">
  3. <descr ref="a"/>
  4. <descr ref="b"/>
  5. </item>
  6. <item id="2">
  7. <descr ref="c"/>
  8. <descr ref="d"/>
  9. </item>
  10. <item id="3">
  11. <descr ref="e">two</descr>
  12. <descr ref="f">two</descr>
  13. <descr ref="x">two</descr>
  14. </item>
  15. <item id="4">
  16. <descr ref="z"/>
  17. <descr ref="y"/>
  18. </item>
  19. </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:

  1. &lt;list&gt;
  2. &lt;item id=&quot;1&quot;&gt;
  3. &lt;descr ref=&quot;a&quot;/&gt;
  4. &lt;descr ref=&quot;b&quot;/&gt;
  5. &lt;/item&gt;
  6. &lt;item id=&quot;2&quot;&gt;
  7. &lt;descr ref=&quot;c&quot;/&gt;
  8. &lt;descr ref=&quot;d&quot;/&gt;
  9. &lt;/item&gt;
  10. &lt;item id=&quot;3&quot;&gt;
  11. &lt;descr ref=&quot;e&quot;&gt;one&lt;/descr&gt;
  12. &lt;descr ref=&quot;f&quot;&gt;one&lt;/descr&gt;
  13. &lt;/item&gt;
  14. &lt;/list&gt;

and:

  1. &lt;list&gt;
  2. &lt;item id=&quot;3&quot;&gt;
  3. &lt;descr ref=&quot;e&quot;&gt;two&lt;/descr&gt;
  4. &lt;descr ref=&quot;f&quot;&gt;two&lt;/descr&gt;
  5. &lt;descr ref=&quot;x&quot;&gt;two&lt;/descr&gt;
  6. &lt;/item&gt;
  7. &lt;item id=&quot;4&quot;&gt;
  8. &lt;descr ref=&quot;z&quot;/&gt;
  9. &lt;descr ref=&quot;y&quot;/&gt;
  10. &lt;/item&gt;
  11. &lt;/list&gt;

And here is my XSLT:

  1. &lt;xsl:stylesheet xmlns:xsl=&quot;http://www.w3.org/1999/XSL/Transform&quot; xmlns:xs=&quot;http://www.w3.org/2001/XMLSchema&quot; exclude-result-prefixes=&quot;xs&quot; version=&quot;3.1&quot;&gt;
  2. &lt;xsl:output method=&quot;xml&quot; indent=&quot;yes&quot; encoding=&quot;UTF-8&quot;/&gt;
  3. &lt;xsl:mode on-no-match=&quot;shallow-copy&quot;/&gt;
  4. &lt;xsl:template match=&quot;/&quot;&gt;
  5. &lt;list&gt;
  6. &lt;xsl:merge&gt;
  7. &lt;xsl:merge-source name=&quot;master&quot; for-each-source=&quot;&#39;list1.xml&#39;&quot; sort-before-merge=&quot;yes&quot; select=&quot;/list/item&quot;&gt;
  8. &lt;xsl:merge-key select=&quot;@id&quot; order=&quot;ascending&quot;/&gt;
  9. &lt;/xsl:merge-source&gt;
  10. &lt;xsl:merge-source name=&quot;update&quot; for-each-source=&quot;&#39;list2.xml&#39;&quot; sort-before-merge=&quot;yes&quot; select=&quot;/list/item&quot;&gt;
  11. &lt;xsl:merge-key select=&quot;@id&quot; order=&quot;ascending&quot;/&gt;
  12. &lt;/xsl:merge-source&gt;
  13. &lt;xsl:merge-action&gt;
  14. &lt;xsl:choose&gt;
  15. &lt;xsl:when test=&quot;empty(current-merge-group(&#39;update&#39;))&quot;&gt;
  16. &lt;xsl:copy-of select=&quot;current-merge-group(&#39;master&#39;)&quot;/&gt;
  17. &lt;xsl:message&gt;master!&lt;/xsl:message&gt;
  18. &lt;/xsl:when&gt;
  19. &lt;xsl:when test=&quot;empty(current-merge-group(&#39;master&#39;))&quot;&gt;
  20. &lt;xsl:copy-of select=&quot;current-merge-group(&#39;update&#39;)&quot;/&gt;
  21. &lt;xsl:message&gt;update!&lt;/xsl:message&gt;
  22. &lt;/xsl:when&gt;
  23. &lt;xsl:otherwise&gt;
  24. &lt;item&gt;
  25. &lt;xsl:merge&gt;
  26. &lt;xsl:merge-source name=&quot;descr-master&quot; sort-before-merge=&quot;yes&quot; select=&quot;descr&quot;&gt;
  27. &lt;xsl:merge-key select=&quot;@ref&quot; order=&quot;ascending&quot;/&gt;
  28. &lt;/xsl:merge-source&gt;
  29. &lt;xsl:merge-source name=&quot;descr-update&quot; sort-before-merge=&quot;yes&quot; select=&quot;descr&quot;&gt;
  30. &lt;xsl:merge-key select=&quot;@ref&quot; order=&quot;ascending&quot;/&gt;
  31. &lt;/xsl:merge-source&gt;
  32. &lt;xsl:merge-action&gt;
  33. &lt;xsl:choose&gt;
  34. &lt;xsl:when test=&quot;empty(current-merge-group(&#39;descr-update&#39;))&quot;&gt;
  35. &lt;xsl:copy-of select=&quot;current-merge-group(&#39;descr-master&#39;)&quot;/&gt;
  36. &lt;xsl:message&gt;descr master!&lt;/xsl:message&gt;
  37. &lt;/xsl:when&gt;
  38. &lt;xsl:when test=&quot;empty(current-merge-group(&#39;descr-master&#39;))&quot;&gt;
  39. &lt;xsl:copy-of select=&quot;current-merge-group(&#39;descr-update&#39;)&quot;/&gt;
  40. &lt;xsl:message&gt;descr update!&lt;/xsl:message&gt;
  41. &lt;/xsl:when&gt;
  42. &lt;xsl:otherwise&gt;
  43. &lt;xsl:copy-of select=&quot;current-merge-group(&#39;descr-update&#39;)&quot;/&gt;
  44. &lt;xsl:message&gt;present in both: kept update!&lt;/xsl:message&gt;
  45. &lt;/xsl:otherwise&gt;
  46. &lt;/xsl:choose&gt;
  47. &lt;/xsl:merge-action&gt;
  48. &lt;/xsl:merge&gt;
  49. &lt;/item&gt;
  50. &lt;/xsl:otherwise&gt;
  51. &lt;/xsl:choose&gt;
  52. &lt;/xsl:merge-action&gt;
  53. &lt;/xsl:merge&gt;
  54. &lt;/list&gt;
  55. &lt;/xsl:template&gt;
  56. &lt;/xsl:stylesheet&gt;

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:

  1. &lt;list&gt;
  2. &lt;item id=&quot;1&quot;&gt;
  3. &lt;descr ref=&quot;a&quot;/&gt;
  4. &lt;descr ref=&quot;b&quot;/&gt;
  5. &lt;/item&gt;
  6. &lt;item id=&quot;2&quot;&gt;
  7. &lt;descr ref=&quot;c&quot;/&gt;
  8. &lt;descr ref=&quot;d&quot;/&gt;
  9. &lt;/item&gt;
  10. &lt;item id=&quot;3&quot;&gt;
  11. &lt;descr ref=&quot;e&quot;&gt;two&lt;/descr&gt;
  12. &lt;descr ref=&quot;f&quot;&gt;two&lt;/descr&gt;
  13. &lt;descr ref=&quot;x&quot;&gt;two&lt;/descr&gt;
  14. &lt;/item&gt;
  15. &lt;item id=&quot;4&quot;&gt;
  16. &lt;descr ref=&quot;z&quot;/&gt;
  17. &lt;descr ref=&quot;y&quot;/&gt;
  18. &lt;/item&gt;
  19. &lt;/list&gt;

答案1

得分: 1

你需要从外部合并组中提取数据:

  1. <xsl:otherwise>
  2. <item>
  3. <xsl:merge>
  4. <xsl:merge-source name="descr-master" sort-before-merge="yes" select="current-merge-group('master')/descr">
  5. <xsl:merge-key select="@ref" order="ascending"/>
  6. </xsl:merge-source>
  7. <xsl:merge-source name="descr-update" sort-before-merge="yes" select="current-merge-group('update')/descr">
  8. <xsl:merge-key select="@ref" order="ascending"/>
  9. </xsl:merge-source>
  10. <xsl:merge-action>
  11. <xsl:choose>
  12. <xsl:when test="empty(current-merge-group('descr-update'))">
  13. <xsl:copy-of select="current-merge-group('descr-master')"/>
  14. <xsl:message>descr master!</xsl:message>
  15. </xsl:when>
  16. <xsl:when test="empty(current-merge-group('descr-master'))">
  17. <xsl:copy-of select="current-merge-group('descr-update')"/>
  18. <xsl:message>descr update!</xsl:message>
  19. </xsl:when>
  20. <xsl:otherwise>
  21. <xsl:copy-of select="current-merge-group('descr-update')"/>
  22. <xsl:message>present in both: kept update!</xsl:message>
  23. </xsl:otherwise>
  24. </xsl:choose>
  25. </xsl:merge-action>
  26. </xsl:merge>
  27. </item>
  28. </xsl:otherwise>

(Note: This is the translation of the provided XML code.)

英文:

You need to pick up the data from the outer merge groups:

  1. &lt;xsl:otherwise&gt;
  2. &lt;item&gt;
  3. &lt;xsl:merge&gt;
  4. &lt;xsl:merge-source name=&quot;descr-master&quot; sort-before-merge=&quot;yes&quot; select=&quot;current-merge-group(&#39;master&#39;)/descr&quot;&gt;
  5. &lt;xsl:merge-key select=&quot;@ref&quot; order=&quot;ascending&quot;/&gt;
  6. &lt;/xsl:merge-source&gt;
  7. &lt;xsl:merge-source name=&quot;descr-update&quot; sort-before-merge=&quot;yes&quot; select=&quot;current-merge-group(&#39;update&#39;)/descr&quot;&gt;
  8. &lt;xsl:merge-key select=&quot;@ref&quot; order=&quot;ascending&quot;/&gt;
  9. &lt;/xsl:merge-source&gt;
  10. &lt;xsl:merge-action&gt;
  11. &lt;xsl:choose&gt;
  12. &lt;xsl:when test=&quot;empty(current-merge-group(&#39;descr-update&#39;))&quot;&gt;
  13. &lt;xsl:copy-of select=&quot;current-merge-group(&#39;descr-master&#39;)&quot;/&gt;
  14. &lt;xsl:message&gt;descr master!&lt;/xsl:message&gt;
  15. &lt;/xsl:when&gt;
  16. &lt;xsl:when test=&quot;empty(current-merge-group(&#39;descr-master&#39;))&quot;&gt;
  17. &lt;xsl:copy-of select=&quot;current-merge-group(&#39;descr-update&#39;)&quot;/&gt;
  18. &lt;xsl:message&gt;descr update!&lt;/xsl:message&gt;
  19. &lt;/xsl:when&gt;
  20. &lt;xsl:otherwise&gt;
  21. &lt;xsl:copy-of select=&quot;current-merge-group(&#39;descr-update&#39;)&quot;/&gt;
  22. &lt;xsl:message&gt;present in both: kept update!&lt;/xsl:message&gt;
  23. &lt;/xsl:otherwise&gt;
  24. &lt;/xsl:choose&gt;
  25. &lt;/xsl:merge-action&gt;
  26. &lt;/xsl:merge&gt;
  27. &lt;/item&gt;
  28. &lt;/xsl:otherwise&gt;

答案2

得分: 0

它有效!只需完成解决方案,以便复制 @id/item,这部分遗漏了:

  1. <xsl:copy>
  2. <xsl:apply-templates select="@*"/>
  3. <xsl:merge>

非常感谢!

英文:

It works!
Just to complete the solution, in order to copy the @id/item, this was missing:

  1. &lt;xsl:copy&gt;
  2. &lt;xsl:apply-templates select=&quot;@*&quot;/&gt;
  3. &lt;xsl:merge&gt;

Thanks a lot!

huangapple
  • 本文由 发表于 2023年3月12日 19:55:51
  • 转载请务必保留本文链接:https://go.coder-hub.com/75712932.html
匿名

发表评论

匿名网友

:?: :razz: :sad: :evil: :!: :smile: :oops: :grin: :eek: :shock: :???: :cool: :lol: :mad: :twisted: :roll: :wink: :idea: :arrow: :neutral: :cry: :mrgreen:

确定