XSLT - 如何使用特定属性包装相邻元素

时间:2012-07-21 23:14:48

标签: xslt

我是xsl的新手。我找到了类似的东西,但不能完全调整它以供我使用。

输入:

<section>
  <heading>some heading text</heading>
  <amendment chapter="1">
    <foo/>
  </amendment>
  <amendment chapter="2">
    <bar/>
  </amendment>
  <amendment chapter="3">
    <baz/>
  </amendment>
  <heading>some heading text</heading>
  <amendment chapter="1">
    <baz/>
  </amendment>
</section>

使用属性“chapter ='1'或chapter ='2'”包装元素。 输出:

<section>
  <heading>some heading text</heading>
  <newwrapper>
    <amendment chapter="1">
      <foo/>
    </amendment>
    <amendment chapter="2">
      <bar/>
    </amendment>
  </newwrapper>
  <amendment chapter="3">
    <baz/>
  </amendment>
  <heading>some heading text</heading>
  <newwrapper>
    <amendment chapter="1">
      <baz/>
    </amendment>
  </newwrapper>
</section>

2 个答案:

答案 0 :(得分:1)

<强>予。这个XSLT 2.0转换:

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

 <xsl:template match="/*">
   <section>
    <xsl:for-each-group select="*" 
                        group-adjacent="self::amendment and @chapter =(1,2)">
     <xsl:choose>
       <xsl:when test="current-grouping-key()">
         <newwrapper>
           <xsl:sequence select="current-group()"/>
         </newwrapper>
       </xsl:when>
       <xsl:otherwise>
         <xsl:sequence select="current-group()"/>
       </xsl:otherwise>
     </xsl:choose>
    </xsl:for-each-group>
  </section>
 </xsl:template>
</xsl:stylesheet>

应用于提供的XML文档时:

<section>
    <heading>some heading text</heading>
    <amendment chapter="1">
        <foo/>
    </amendment>
    <amendment chapter="2">
        <bar/>
    </amendment>
    <amendment chapter="3">
        <baz/>
    </amendment>
    <heading>some heading text</heading>
    <amendment chapter="1">
        <baz/>
    </amendment>
</section>

会产生想要的正确结果:

<section>
   <heading>some heading text</heading>
   <newwrapper>
      <amendment chapter="1">
               <foo/>
         </amendment>
      <amendment chapter="2">
               <bar/>
         </amendment>
   </newwrapper>
   <amendment chapter="3">
            <baz/>
      </amendment>
   <heading>some heading text</heading>
   <newwrapper>
      <amendment chapter="1">
               <baz/>
         </amendment>
   </newwrapper>
</section>

解释

正确使用 xsl:for-each-group group-adjacent属性。


<强> II。 XSLT 1.0解决方案:

<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="kFollowing" match="amendment[not(@chapter >2)]" use=
 "generate-id(preceding-sibling::*
                [not(self::amendment and @chapter &lt;= 2)][1])"/>

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


 <xsl:template match=
 "*[not(self::amendment and @chapter &lt;= 2)
  and
    following-sibling::*[1][self::amendment and not(@chapter >2)]
    ]">
  <xsl:call-template name="identity"/>
  <newwrapper>
   <xsl:apply-templates mode="inGroup"
                        select="key('kFollowing', generate-id())"/>
  </newwrapper>
 </xsl:template>

 <xsl:template match="*" mode="inGroup">
  <xsl:call-template name="identity"/>
 </xsl:template>
 <xsl:template match="amendment[not(@chapter >2)]"/>
</xsl:stylesheet>

当在同一个XML文档(上面)上应用此转换时,会产生相同的,错误的结果

解释

正确使用:

  1. 利用和​​覆盖 identity rule

  2. Keys 定义一组amendment元素,chapter属性不大于2,作为函数的函数该组的前一个兄弟元素的 generate-id()

答案 1 :(得分:0)

Dimitre Novatchev,我将属性修改为字符串,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="kFollowing" match="amendment[(@chapter='1' or @chapter='2')]" use="generate-id(preceding-sibling::*[not(self::amendment and (@chapter='1' or @chapter='2'))][1])"/>
    <xsl:template match="node()|@*" name="identity">
        <xsl:copy>
            <xsl:apply-templates select="node()|@*"/>
        </xsl:copy>
    </xsl:template>
    <xsl:template match="*[not(self::amendment and (@chapter='1' or @chapter='2')) and following-sibling::*[1][self::amendment and (@chapter='1' or @chapter='2')]]">
        <xsl:call-template name="identity"/>
        <newwrapper>
            <xsl:apply-templates mode="inGroup" select="key('kFollowing', generate-id())"/>
        </newwrapper>
    </xsl:template>
    <xsl:template match="*" mode="inGroup">
        <xsl:call-template name="identity"/>
    </xsl:template>
    <xsl:template match="amendment[(@chapter='1' or @chapter='2')]"/>
</xsl:stylesheet>