【问题标题】:Transform to remove duplicate and copy rest转换以删除重复并复制其余部分
【发布时间】:2012-06-12 16:50:19
【问题描述】:

我希望输出 xml 根据属性“f”为元素“c”分组。这是我的输入 xml 和 xslt。我希望该组只出现一次,并且其他节点应该按原样复制到输出中。我尝试的 xslt 复制了整个输入 xml。因此,如果有两个或多个具有 c 元素且 'f' 的属性值相同的元素,则希望该组第一次出现在输出中。我想要的结果也被复制了。

输入xml

<M>
   <a>
      <b>
         <c f="123">
            <d>Al</d>
            <e NO="678">
               <f>Y</f>
               <g>
                  <h>FTO</h>
               </g>
            </e>
         </c>
      </b>
   </a>
  <a>
    <b>
      <c f="123">
        <d>Al</d>
        <e NO="678">
          <f>Y</f>
          <g>
            <h>FTO</h>
          </g>
        </e>
      </c>
    </b>
  </a>
  <a>
    <b>
      <c f="567">
        <d>Al</d>
        <e NO="678">
          <f>Y</f>
          <g>
            <h>FTO</h>
          </g>
        </e>
      </c>
    </b>
  </a>
  <a>
    <b>
      <somethingelse></somethingelse>
    </b>
  </a>
</M>

想要的输出xml

<M>
  <a>
    <b>
      <c f="123">
        <d>Al</d>
        <e NO="678">
          <f>Y</f>
          <g>
            <h>FTO</h>
          </g>
        </e>
      </c>
    </b>
  </a>
  <a>
    <b>
      <c f="567">
        <d>Al</d>
        <e NO="678">
          <f>Y</f>
          <g>
            <h>FTO</h>
          </g>
        </e>
      </c>
    </b>
  </a>
  <a>
    <b>
      <somethingelse></somethingelse>
    </b>
  </a>
</M>

我试过了

<xsl:stylesheet version="1.0"
 xmlns:xsl="http://www.w3.org/1999/XSL/Transform">
  <xsl:output omit-xml-declaration="yes" indent="yes"/>
  <xsl:strip-space elements="*"/>

  <xsl:key name="mykey" match="c"
   use="@f"/>

  <xsl:template match=
  "c[generate-id()
      =
       generate-id(key('mykey',@f)[1])
      ]
  ">



    <xsl:text/>
    <xsl:copy-of select="key('mykey',@f)[1]"/>
  </xsl:template>
  <xsl:template match="node()|@*">
        <xsl:copy>
          <xsl:apply-templates select="node()|@*"/>
        </xsl:copy>
  </xsl:template>
</xsl:stylesheet>

【问题讨论】:

    标签: xml xslt xslt-1.0


    【解决方案1】:

    这种转变

    <xsl:stylesheet version="1.0"
         xmlns:xsl="http://www.w3.org/1999/XSL/Transform">
         <xsl:output omit-xml-declaration="yes" indent="yes"/>
         <xsl:strip-space elements="*"/>
    
         <xsl:key name="kAByC-F" match="a" use="*/c/@f"/>
    
         <xsl:template match="node()|@*">
             <xsl:copy>
               <xsl:apply-templates select="node()|@*"/>
             </xsl:copy>
         </xsl:template>
    
         <xsl:template match=
          "a[*/c
           and
             not(generate-id()
                =
                 generate-id(key('kAByC-F', */c/@f)[1])
                 )
            ]"/>
    </xsl:stylesheet>
    

    应用于提供的 XML 文档时

    <M>
       <a>
          <b>
             <c f="123">
                <d>Al</d>
                <e NO="678">
                   <f>Y</f>
                   <g>
                      <h>FTO</h>
                   </g>
                </e>
             </c>
          </b>
       </a>
      <a>
        <b>
          <c f="123">
            <d>Al</d>
            <e NO="678">
              <f>Y</f>
              <g>
                <h>FTO</h>
              </g>
            </e>
          </c>
        </b>
      </a>
      <a>
        <b>
          <c f="567">
            <d>Al</d>
            <e NO="678">
              <f>Y</f>
              <g>
                <h>FTO</h>
              </g>
            </e>
          </c>
        </b>
      </a>
      <a>
        <b>
          <somethingelse></somethingelse>
        </b>
      </a>
    </M>
    

    产生想要的正确结果

    <M>
       <a>
          <b>
             <c f="123">
                <d>Al</d>
                <e NO="678">
                   <f>Y</f>
                   <g>
                      <h>FTO</h>
                   </g>
                </e>
             </c>
          </b>
       </a>
       <a>
          <b>
             <c f="567">
                <d>Al</d>
                <e NO="678">
                   <f>Y</f>
                   <g>
                      <h>FTO</h>
                   </g>
                </e>
             </c>
          </b>
       </a>
       <a>
          <b>
             <somethingelse/>
          </b>
       </a>
    </M>
    

    解释

    正确使用Muenchian grouping method

    【讨论】:

      【解决方案2】:

      一个简单的解决方案是为所有以下c 节点添加一个空模板:

      <xsl:template match="c[generate-id() = generate-id(key('mykey',@f)[position() &gt; 1])]" />
      

      【讨论】:

      • 只有这样才能删除重复的c 元素——但是,任务是删除完整的子树,根植于每个重复的a 祖先。这就是我的答案中提供的解决方案正在做的事情。
      • 嗯......我得再考虑一下(我仍然受到 Muenchian Grouping 的挑战,但渴望学习)。有趣的是,它似乎产生了所需的输出。顺便说一句:您的(显示的)输出错过了包含 &lt;somethingelse&gt; 的部分(还没有尝试您的 xslt)。
      【解决方案3】:

      一个想法可能是将 c 的所有值以一种允许您将它们彼此区分开来的格式保存在变量中,然后每次遇到 c 时,检查该值是否包含在变量中.如果是,则跳到下一个节点。如果不是,则继续处理当前节点。

      如果您需要更多具体信息,请告诉我

      编辑:作为一种替代方法,可能是一种更简单的方法(我最近一直在使用 NAnt,所以我可能会给你一个 NAnt 策略)是按所有节点的 s 值对它们进行排序。然后只需有一个变量来存储 c 的当前值并进行比较,直到您正在查看的值不等于存储的值。然后重新分配值并再次执行!

      【讨论】:

        【解决方案4】:

        您可以匹配&lt;a&gt; 元素,并检查其&lt;c&gt; 子元素中是否存在具有相同f 属性的任何前面的兄弟。如果有,您发现给定 f 值的重复项(给定 f 值的出现不是该值的第一次出现),您可以覆盖标识模板以跳过该元素:

        <xsl:stylesheet version="1.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform">
            <xsl:output omit-xml-declaration="yes" indent="yes"/>
        
            <xsl:template match="node()|@*">
                <xsl:copy>
                    <xsl:apply-templates select="node()|@*"/>
                </xsl:copy>
            </xsl:template>
        
            <xsl:template match="/M/a[b/c/@f = preceding-sibling::a/b/c/@f]"/>
        
        </xsl:stylesheet>
        

        此解决方案的一个优点是它不需要任何有关密钥或 ID 生成的知识;它只适用于基本的 XPath 轴功能。但是,当要比较的元素并非都在相同的嵌套深度/相同的相对元素层次结构中时,它可能会稍微复杂一些。

        P.S.:我删除了 &lt;xsl:strip-space elements="*"/&gt; 元素,因为我无法测试它(我的 Xml 处理器声称我只能在传递可读流而不是文件时使用它),但如果出现,请随时重新插入它它适合你。

        【讨论】:

        • 你不能用&lt;xsl:template match="/M/a[b/c/@f = preceding-sibling::a/b/c/@f]"/&gt;替换整个第二个模板吗?
        • @DevNull:可能。不过,我想我已经遇到并阅读了一些关于模板match 属性中的 XPath 表达式的内容,这些属性不支持某些类型的约束。现在找不到了,但是当时让我很头疼:-/
        • @DevNull:你是对的;我所记得的完全与使用参数值有关。我已经简化了答案中的代码。谢谢。
        猜你喜欢
        • 2020-12-07
        • 1970-01-01
        • 2017-01-10
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 2020-03-22
        相关资源
        最近更新 更多