XSL - 删除包含特定条件的父节点

时间:2012-07-22 02:51:59

标签: xml xslt

我有一个XML,我想用xslt转换它。 输入看起来像这样。

<xmeml>
<Doc>
    <Test>
        <Unit>abc</Unit>
        <Unit2>1234</Unit2>
        <Unit3>tuvw</Unit3>
    </Test>
    <Test>
        <Unit>bcd</Unit>
        <Unit2>2345</Unit2>
        <Unit3>wxyz</Unit3>
    </Test>
</Doc>
<Doc>
    <Test>
        <Unit>abc</Unit>
        <Unit2>3456</Unit2>
        <Unit3>wxyz</Unit3>
    </Test>
    <Test>
        <Unit>cde</Unit>
        <Unit2>3456</Unit2>
        <Unit3>wxyz</Unit3>
    </Test> 
</Doc>
<Doc>
    <Test>
        <Unit>abc</Unit>
        <Unit2>1234</Unit2>
        <Unit3>wxyz</Unit3>
    </Test>
    <Test>
        <Unit>def</Unit>
        <Unit2>4567</Unit2>
        <Unit3>wxyz</Unit3>
    </Test> 
</Doc>
<Doc>
    <Test>
        <Unit>abc</Unit>
        <Unit2>1234</Unit2>
        <Unit3>uvwx</Unit3>
    </Test>
    <Test>
        <Unit>efg</Unit>
        <Unit2>2345</Unit2>
        <Unit3>wxyz</Unit3>
    </Test> 
</Doc>
</xmeml>

输出应该如下所示。

<xmeml>
<Doc>
    <Test>
        <Unit>bcd</Unit>
        <Unit2>2345</Unit2>
        <Unit3>wxyz</Unit3>
    </Test>
</Doc>
<Doc>
    <Test>
        <Unit>abc</Unit>
        <Unit2>3456</Unit2>
        <Unit3>wxyz</Unit3>
    </Test>
    <Test>
        <Unit>cde</Unit>
        <Unit2>3456</Unit2>
        <Unit3>wxyz</Unit3>
    </Test> 
</Doc>
<Doc>
    <Test>
        <Unit>abc</Unit>
        <Unit2>1234</Unit2>
        <Unit3>wxyz</Unit3>
    </Test>
    <Test>
        <Unit>def</Unit>
        <Unit2>4567</Unit2>
        <Unit3>wxyz</Unit3>
    </Test> 
</Doc>
<Doc>
    <Test>
        <Unit>efg</Unit>
        <Unit2>2345</Unit2>
        <Unit3>wxyz</Unit3>
    </Test> 
</Doc>
</xmeml>

我想要删除符合以下条件的任何Test节点。 - Unit3子节点以tuv或uvw启动。 - AND单元和单元2值都在另一个测试节点中重复/重复发生

提前感谢您的帮助。

2 个答案:

答案 0 :(得分:1)

此转换(基于Muenchian分组):

<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="kTest"
   match="Test[starts-with(Unit3, 'tuv') or starts-with(Unit3, 'uvw')]"
          use="concat(Unit, '+', Unit2)"/>

 <xsl:template match="node()|@*">
  <xsl:copy>
   <xsl:apply-templates select="node()|@*"/>
  </xsl:copy>
 </xsl:template>

 <xsl:template match=
  "Test[starts-with(Unit3, 'tuv') or starts-with(Unit3, 'uvw')]
    [not(generate-id()
    =
     generate-id(key('kTest', concat(Unit, '+', Unit2))[last()]))]"/>
</xsl:stylesheet>

应用于提供的XML文档

<xmeml>
    <Doc>
        <Test>
            <Unit>abc</Unit>
            <Unit2>1234</Unit2>
            <Unit3>tuvw</Unit3>
        </Test>
        <Test>
            <Unit>bcd</Unit>
            <Unit2>2345</Unit2>
            <Unit3>wxyz</Unit3>
        </Test>
    </Doc>
    <Doc>
        <Test>
            <Unit>abc</Unit>
            <Unit2>3456</Unit2>
            <Unit3>wxyz</Unit3>
        </Test>
        <Test>
            <Unit>cde</Unit>
            <Unit2>3456</Unit2>
            <Unit3>wxyz</Unit3>
        </Test>
    </Doc>
    <Doc>
        <Test>
            <Unit>abc</Unit>
            <Unit2>1234</Unit2>
            <Unit3>wxyz</Unit3>
        </Test>
        <Test>
            <Unit>def</Unit>
            <Unit2>4567</Unit2>
            <Unit3>wxyz</Unit3>
        </Test>
    </Doc>
    <Doc>
        <Test>
            <Unit>abc</Unit>
            <Unit2>1234</Unit2>
            <Unit3>uvwx</Unit3>
        </Test>
        <Test>
            <Unit>efg</Unit>
            <Unit2>2345</Unit2>
            <Unit3>wxyz</Unit3>
        </Test>
    </Doc>
</xmeml>

生成正确的结果(实现所有要求):

<xmeml>
   <Doc>
      <Test>
         <Unit>bcd</Unit>
         <Unit2>2345</Unit2>
         <Unit3>wxyz</Unit3>
      </Test>
   </Doc>
   <Doc>
      <Test>
         <Unit>abc</Unit>
         <Unit2>3456</Unit2>
         <Unit3>wxyz</Unit3>
      </Test>
      <Test>
         <Unit>cde</Unit>
         <Unit2>3456</Unit2>
         <Unit3>wxyz</Unit3>
      </Test>
   </Doc>
   <Doc>
      <Test>
         <Unit>abc</Unit>
         <Unit2>1234</Unit2>
         <Unit3>wxyz</Unit3>
      </Test>
      <Test>
         <Unit>def</Unit>
         <Unit2>4567</Unit2>
         <Unit3>wxyz</Unit3>
      </Test>
   </Doc>
   <Doc>
      <Test>
         <Unit>abc</Unit>
         <Unit2>1234</Unit2>
         <Unit3>uvwx</Unit3>
      </Test>
      <Test>
         <Unit>efg</Unit>
         <Unit2>2345</Unit2>
         <Unit3>wxyz</Unit3>
      </Test>
   </Doc>
</xmeml>

<强>更新

OP对这个问题有自己的解释,这个问题含糊不清,而且没有精确定义。

经过相当多的猜测,这可能是他想要的......:

<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="kTest"
   match="Test" use="concat(Unit, '+', Unit2)"/>

 <xsl:template match="node()|@*">
  <xsl:copy>
   <xsl:apply-templates select="node()|@*"/>
  </xsl:copy>
 </xsl:template>

 <xsl:template match=
  "Test[starts-with(Unit3, 'tuv') or starts-with(Unit3, 'uvw')]
    [not(generate-id()
    =
     generate-id(key('kTest', concat(Unit, '+', Unit2))
                                     [not(position()=1)])
                )]"/>
</xsl:stylesheet>

当在提供的XML文档(上面)上应用此转换时,现在结果与OP认为的想要结果相同

<xmeml>
   <Doc>
      <Test>
         <Unit>bcd</Unit>
         <Unit2>2345</Unit2>
         <Unit3>wxyz</Unit3>
      </Test>
   </Doc>
   <Doc>
      <Test>
         <Unit>abc</Unit>
         <Unit2>3456</Unit2>
         <Unit3>wxyz</Unit3>
      </Test>
      <Test>
         <Unit>cde</Unit>
         <Unit2>3456</Unit2>
         <Unit3>wxyz</Unit3>
      </Test>
   </Doc>
   <Doc>
      <Test>
         <Unit>abc</Unit>
         <Unit2>1234</Unit2>
         <Unit3>wxyz</Unit3>
      </Test>
      <Test>
         <Unit>def</Unit>
         <Unit2>4567</Unit2>
         <Unit3>wxyz</Unit3>
      </Test>
   </Doc>
   <Doc>
      <Test>
         <Unit>efg</Unit>
         <Unit2>2345</Unit2>
         <Unit3>wxyz</Unit3>
      </Test>
   </Doc>
</xmeml>

答案 1 :(得分:1)

Dimitre解决方案的这个调整怎么样......

<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="kTest" match="Test" use="concat(Unit, '+', Unit2)"/>

 <xsl:template match="node()|@*">
  <xsl:copy>
   <xsl:apply-templates select="node()|@*"/>
  </xsl:copy>
 </xsl:template>

 <xsl:template match=
  "Test[key('kTest', concat(Unit, '+', Unit2))[2]]
   [starts-with(Unit3, 'tuv') or starts-with(Unit3, 'uvw')]"/>
</xsl:stylesheet>

据我所知,转型规则是:

  1. 按原样复制所有节点,除非如下所示。
  2. 排除所有测试节点具有以下属性:
  3. 2.1文档中存在另一个Test节点(称为Test(other)),以便:

      (Test(reference) / Unit = Test(other) / Unit)   AND
      (Test(reference) / Unit2 = Test(other) / Unit2)
    

    2.2参考测试节点的Unit3子节点以tuv或uvw

    开头

    此输出与发布的OP完全相同。有趣的是,如果我正确地理解了这个问题,Dimitre最近刚刚提供了解决方案,解决了与此问题相同的问题XSL comparison of nodes。同样,如果我正确理解了您的问题,标题会产生误导。 “去除重复”通常被认为意味着重复数据删除,如(1,2,2,3) - >中所述。 (1,2,3);而你想要的,如(1,2,2,3) - &gt; (1,3)通常被描述为“选择唯一节点/值”。