变换去除重复复制和休息(Transform to remove duplicate and copy

2019-06-25 10:23发布

我想输出XML已分组的元素“C”,根据属性“F”。 这是我的输入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>

XSLT我试着

<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>

Answer 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分组的方法



Answer 2:

一个简单的办法是只添加一个空模板后面的所有c节点:

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


Answer 3:

一种想法可能是保存所有C值在一个变量的格式,使您可以从一个另一个区分开来,然后每遇到C时间,你检查,看看是否能值包含的变量中。 如果是,则跳到下一个节点。 如果不是,继续处理当前节点。

告诉我,如果你需要更具体的信息

编辑:作为替代方案,而且可能更简单的方法(我一直在使用楠最近,所以我可能给你一个楠策略)是由他们的价值观所有节点进行排序。 然后,只需具有存储C的当前值的变量和比较,直到你在寻找的价值不等于存储的值。 然后重新分配的价值,并再次做到这一点!



Answer 4:

可以匹配<a>元件和检查是否有具有相同的前述任一兄弟姐妹f在它们的属性<c>的子元素。 如果有,你已经找到了一个给定的副本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轴功能。 然而,当元素比较不是都在同一嵌套深度/在相同的相对元素层次,它可能会稍微复杂一些。

PS:我除去<xsl:strip-space elements="*"/>元素,因为我无法测试它(我的XML处理器权利如果我通过一个可读的流,而不是一个文件I只能使用它),但感觉免费重新插入它,如果你的作品。



文章来源: Transform to remove duplicate and copy rest