合并两个XML文件使用XSLT 3.0

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

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:

&lt;list&gt;
   &lt;item id=&quot;1&quot;&gt;
      &lt;descr ref=&quot;a&quot;/&gt;
      &lt;descr ref=&quot;b&quot;/&gt;
   &lt;/item&gt;
   &lt;item id=&quot;2&quot;&gt;
      &lt;descr ref=&quot;c&quot;/&gt;
      &lt;descr ref=&quot;d&quot;/&gt;
   &lt;/item&gt;
   &lt;item id=&quot;3&quot;&gt;
      &lt;descr ref=&quot;e&quot;&gt;one&lt;/descr&gt;
      &lt;descr ref=&quot;f&quot;&gt;one&lt;/descr&gt;
   &lt;/item&gt;
&lt;/list&gt;

and:

&lt;list&gt;
   &lt;item id=&quot;3&quot;&gt;
      &lt;descr ref=&quot;e&quot;&gt;two&lt;/descr&gt;
      &lt;descr ref=&quot;f&quot;&gt;two&lt;/descr&gt;
      &lt;descr ref=&quot;x&quot;&gt;two&lt;/descr&gt;
   &lt;/item&gt;
   &lt;item id=&quot;4&quot;&gt;
      &lt;descr ref=&quot;z&quot;/&gt;
      &lt;descr ref=&quot;y&quot;/&gt;
   &lt;/item&gt;
&lt;/list&gt;

And here is my XSLT:

&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;
   &lt;xsl:output method=&quot;xml&quot; indent=&quot;yes&quot; encoding=&quot;UTF-8&quot;/&gt;
   &lt;xsl:mode on-no-match=&quot;shallow-copy&quot;/&gt;
   &lt;xsl:template match=&quot;/&quot;&gt;
      &lt;list&gt;
         &lt;xsl:merge&gt;
            &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;
               &lt;xsl:merge-key select=&quot;@id&quot; order=&quot;ascending&quot;/&gt;
            &lt;/xsl:merge-source&gt;
            &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;
               &lt;xsl:merge-key select=&quot;@id&quot; order=&quot;ascending&quot;/&gt;
            &lt;/xsl:merge-source&gt;
            &lt;xsl:merge-action&gt;
               &lt;xsl:choose&gt;
                  &lt;xsl:when test=&quot;empty(current-merge-group(&#39;update&#39;))&quot;&gt;
                     &lt;xsl:copy-of select=&quot;current-merge-group(&#39;master&#39;)&quot;/&gt;
                     &lt;xsl:message&gt;master!&lt;/xsl:message&gt;
                  &lt;/xsl:when&gt;
                  &lt;xsl:when test=&quot;empty(current-merge-group(&#39;master&#39;))&quot;&gt;
                     &lt;xsl:copy-of select=&quot;current-merge-group(&#39;update&#39;)&quot;/&gt;
                     &lt;xsl:message&gt;update!&lt;/xsl:message&gt;
                  &lt;/xsl:when&gt;
                  &lt;xsl:otherwise&gt;
                     &lt;item&gt;
                        &lt;xsl:merge&gt;
                           &lt;xsl:merge-source name=&quot;descr-master&quot; sort-before-merge=&quot;yes&quot; select=&quot;descr&quot;&gt;
                              &lt;xsl:merge-key select=&quot;@ref&quot; order=&quot;ascending&quot;/&gt;
                           &lt;/xsl:merge-source&gt;
                           &lt;xsl:merge-source name=&quot;descr-update&quot; sort-before-merge=&quot;yes&quot; select=&quot;descr&quot;&gt;
                              &lt;xsl:merge-key select=&quot;@ref&quot; order=&quot;ascending&quot;/&gt;
                           &lt;/xsl:merge-source&gt;
                           &lt;xsl:merge-action&gt;
                              &lt;xsl:choose&gt;
                                 &lt;xsl:when test=&quot;empty(current-merge-group(&#39;descr-update&#39;))&quot;&gt;
                                    &lt;xsl:copy-of select=&quot;current-merge-group(&#39;descr-master&#39;)&quot;/&gt;
                                    &lt;xsl:message&gt;descr master!&lt;/xsl:message&gt;
                                 &lt;/xsl:when&gt;
                                 &lt;xsl:when test=&quot;empty(current-merge-group(&#39;descr-master&#39;))&quot;&gt;
                                    &lt;xsl:copy-of select=&quot;current-merge-group(&#39;descr-update&#39;)&quot;/&gt;
                                    &lt;xsl:message&gt;descr update!&lt;/xsl:message&gt;
                                 &lt;/xsl:when&gt;
                                 &lt;xsl:otherwise&gt;
                                    &lt;xsl:copy-of select=&quot;current-merge-group(&#39;descr-update&#39;)&quot;/&gt;
                                    &lt;xsl:message&gt;present in both: kept update!&lt;/xsl:message&gt;
                                 &lt;/xsl:otherwise&gt;
                              &lt;/xsl:choose&gt;
                           &lt;/xsl:merge-action&gt;
                        &lt;/xsl:merge&gt;
                     &lt;/item&gt;
                  &lt;/xsl:otherwise&gt;
               &lt;/xsl:choose&gt;
            &lt;/xsl:merge-action&gt;
         &lt;/xsl:merge&gt;
      &lt;/list&gt;
   &lt;/xsl:template&gt;
&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:

&lt;list&gt;
   &lt;item id=&quot;1&quot;&gt;
      &lt;descr ref=&quot;a&quot;/&gt;
      &lt;descr ref=&quot;b&quot;/&gt;
   &lt;/item&gt;
   &lt;item id=&quot;2&quot;&gt;
      &lt;descr ref=&quot;c&quot;/&gt;
      &lt;descr ref=&quot;d&quot;/&gt;
   &lt;/item&gt;
   &lt;item id=&quot;3&quot;&gt;
      &lt;descr ref=&quot;e&quot;&gt;two&lt;/descr&gt;
      &lt;descr ref=&quot;f&quot;&gt;two&lt;/descr&gt;
      &lt;descr ref=&quot;x&quot;&gt;two&lt;/descr&gt;
   &lt;/item&gt;
   &lt;item id=&quot;4&quot;&gt;
      &lt;descr ref=&quot;z&quot;/&gt;
      &lt;descr ref=&quot;y&quot;/&gt;
   &lt;/item&gt;
&lt;/list&gt;

答案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:

             &lt;xsl:otherwise&gt;
                 &lt;item&gt;
                    &lt;xsl:merge&gt;
                       &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;
                          &lt;xsl:merge-key select=&quot;@ref&quot; order=&quot;ascending&quot;/&gt;
                       &lt;/xsl:merge-source&gt;
                       &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;
                          &lt;xsl:merge-key select=&quot;@ref&quot; order=&quot;ascending&quot;/&gt;
                       &lt;/xsl:merge-source&gt;
                       &lt;xsl:merge-action&gt;
                          &lt;xsl:choose&gt;
                             &lt;xsl:when test=&quot;empty(current-merge-group(&#39;descr-update&#39;))&quot;&gt;
                                &lt;xsl:copy-of select=&quot;current-merge-group(&#39;descr-master&#39;)&quot;/&gt;
                                &lt;xsl:message&gt;descr master!&lt;/xsl:message&gt;
                             &lt;/xsl:when&gt;
                             &lt;xsl:when test=&quot;empty(current-merge-group(&#39;descr-master&#39;))&quot;&gt;
                                &lt;xsl:copy-of select=&quot;current-merge-group(&#39;descr-update&#39;)&quot;/&gt;
                                &lt;xsl:message&gt;descr update!&lt;/xsl:message&gt;
                             &lt;/xsl:when&gt;
                             &lt;xsl:otherwise&gt;
                                &lt;xsl:copy-of select=&quot;current-merge-group(&#39;descr-update&#39;)&quot;/&gt;
                                &lt;xsl:message&gt;present in both: kept update!&lt;/xsl:message&gt;
                             &lt;/xsl:otherwise&gt;
                          &lt;/xsl:choose&gt;
                       &lt;/xsl:merge-action&gt;
                    &lt;/xsl:merge&gt;
                 &lt;/item&gt;
              &lt;/xsl:otherwise&gt;

答案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:

             &lt;xsl:copy&gt;
                &lt;xsl:apply-templates select=&quot;@*&quot;/&gt;
                &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:

确定