2012-04-04 19 views
3

我有一个XML结构是这样的:如何删除XSLT中的特定子元素?

<root> 
    <element> 
     <name>Foo</name> 
     <subelement> 
      <key>1.1</key> 
      <value>Lorem ipsum</value> 
     </subelement> 
     <subelement> 
      <key>1.2</key> 
      <value>Lorem ipsum dolor</value> 
     </subelement> 
    </element> 
    <element> 
     <name>Bar</name> 
     <subelement> 
      <key>7.3.4</key> 
      <value>Seven three four</value> 
     </subelement> 
     <subelement> 
      <key>7.3.8</key> 
      <value>Seven three eight</value> 
     </subelement> 
     <subelement> 
      <key>7.1</key> 
      <value>Seven one</value> 
     </subelement> 
    </element> 
</root> 

我尽量做到是去除除了一个用“最高”键,所有<subelement>秒。 我似乎无法找到某种<element>内的<subelements> s的<key> s。

生成的XML将如下所示:

<root> 
    <element> 
     <name>Foo</name> 
     <subelement> 
      <key>1.2</key> 
      <value>Lorem ipsum dolor</value> 
     </subelement> 
    </element> 
    <element> 
     <name>Bar</name> 
     <subelement> 
      <key>7.3.8</key> 
      <value>Seven three eight</value> 
     </subelement> 
    </element> 
</root> 

任何提示都非常欢迎。

+0

XSLT 1.0或2.0? – MiMo 2012-04-04 23:57:11

回答

2

此XSLT 2.0变换适用于任何数量的 “关键元件” 的一个键和任何可能的正整数值的任何关键组件

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

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

<xsl:template match= 
"subelement 
    [not(key eq my:max(../subelement/key)) 
    or 
    key = preceding-sibling::subelement/key 
    ]"/> 

<xsl:function name="my:max" as="xs:string"> 
    <xsl:param name="pValues" as="xs:string+"/> 

    <xsl:sequence select= 
    "if(not(distinct-values($pValues)[2])) 
     then $pValues[1] 
    else 
     for $vMax1 in 
      max(for $s in $pValues 
        return 
        xs:integer(substring-before(concat($s,'.'),'.')) 
       ), 

      $vcntMax1Values in 
      count($pValues[starts-with(., string($vMax1))]) 

     return 
      if($vcntMax1Values eq 1) 
      then $pValues[starts-with(., string($vMax1))] 
          [1] 
      else 
      for $submax in 
        (my:max(for $val in 
            $pValues[starts-with(., string($vMax1))] 
               [contains(., '.')], 
            $subval in substring-after($val, '.') 
           return 
            $subval 
          ) 
        ) 
       return 
        concat($vMax1, '.', $submax) 

    "/> 
</xsl:function> 
</xsl:stylesheet> 

当在下面的XML文档应用该变换(所提供的一个,延伸至变得更有趣):

<root> 
    <element> 
     <name>Foo</name> 
     <subelement> 
      <key>1.1</key> 
      <value>Lorem ipsum</value> 
     </subelement> 
     <subelement> 
      <key>1.2</key> 
      <value>Lorem ipsum dolor</value> 
     </subelement> 
    </element> 
    <element> 
     <name>Bar</name> 
     <subelement> 
      <key>7.3.4</key> 
      <value>Seven three four</value> 
     </subelement> 
     <subelement> 
      <key>7.3.8</key> 
      <value>Seven three eight</value> 
     </subelement> 
     <subelement> 
      <key>7.3.8.1</key> 
      <value>Seven three eight one</value> 
     </subelement> 
     <subelement> 
      <key>7.3.8.1</key> 
      <value>Seven three eight one</value> 
     </subelement> 
     <subelement> 
      <key>7.1</key> 
      <value>Seven one</value> 
     </subelement> 
     <subelement> 
      <key>10.1</key> 
      <value>Ten one</value> 
     </subelement> 
     <subelement> 
      <key>10.1</key> 
      <value>Ten one</value> 
     </subelement> 
    </element> 
</root> 

有用,正确的结果产生

<root> 
    <element> 
     <name>Foo</name> 
     <subelement> 
     <key>1.2</key> 
     <value>Lorem ipsum dolor</value> 
     </subelement> 
    </element> 
    <element> 
     <name>Bar</name> 
     <subelement> 
     <key>10.1</key> 
     <value>Ten one</value> 
     </subelement> 
    </element> 
</root> 

说明

这个通用解决方案的核心是函数my:max(),它给出了一个非空的“结构化值”序列(一个结构化值是一个正整数序列,加上'。'字符),产生一个(许多可能的)最大值。

此函数是递归的。它执行以下操作

  1. 如果所有传递的值相同,则他们的第一个返回。

  2. 否则,找到第一个组件的最大值。

  3. 如果只有其中一个值具有找到的最大值的第一个分量,则返回此值。

  4. 否则,找到所有具有最大第一个分量的值的“尾部”的最大值(递归)。

  5. 最后,将最大的第一个分量与上一步中找到的“尾部”的最大值合并在一起,然后返回该值。

+0

+1,我想知道它是否可以用XSLT 1.0 ..你可以请你发布XSLT 1.0的答案吗?这对我有帮助。 :) – 2012-04-05 06:40:17

+0

@ infantprogrammer'Aravind':欢迎您 - 当我找到10-15分钟的空闲时间时,我会发布单独的XSLT 1.0答案。 – 2012-04-05 11:55:05

+0

当然:)慢慢来! – 2012-04-05 15:45:05

-1

以下版本2.0 XSLT

<?xml version="1.0" encoding="UTF-8"?> 
<xsl:stylesheet version="2.0" 
    xmlns:xsl="http://www.w3.org/1999/XSL/Transform"> 
    <xsl:template match="@* | node()"> 
     <xsl:copy> 
      <xsl:apply-templates select="@* | node()"/> 
     </xsl:copy> 
    </xsl:template> 

    <xsl:template match="element"> 
     <xsl:variable name="sorted"> 
      <xsl:for-each select="subelement"> 
       <xsl:sort select="key"/> 
       <xsl:copy-of select="."/> 
      </xsl:for-each> 
     </xsl:variable> 
     <xsl:variable name="highest" select="$sorted/subelement[count($sorted/subelement)]/key"/> 
     <element> 
      <xsl:copy-of select="name"/> 
      <xsl:copy-of select="subelement[key=$highest]"/> 
     </element> 
    </xsl:template> 

</xsl:stylesheet> 

当施加到样品输入XML产生所需的输出XML

<?xml version="1.0" encoding="UTF-8"?> 
<root> 
    <element> 
     <name>Foo</name> 
     <subelement> 
      <key>1.2</key> 
      <value>Lorem ipsum dolor</value> 
     </subelement> 
    </element> 
    <element> 
     <name>Bar</name> 
     <subelement> 
      <key>7.3.8</key> 
      <value>Seven three eight</value> 
     </subelement> 
    </element> 
</root> 
+0

不幸的是,提出的解决方案是错误的。它会选择'7.2'大于'10.1' – 2012-04-05 02:45:02