xslt在兄弟节点内移动节点

时间:2016-02-19 11:33:35

标签: xslt

经过一天的XSLT研究,我承认失败了!

这是我的意见:

<div class="a" >
  <div class="b">b1</div>
  <div class="c">b1c1</div>
  <div class="d">b1d1</div>
  <div class="d">b1d2</div>
  <div class="b">b2</div>
  <div class="c">b2c1</div>
  <div class="d">b2d1</div>
  <div class="d">b2d2</div>
  <div class="d">b2d3</div>
  <div class="b">b3</div>
  <div class="c">b3c1</div>
  <div class="d">b3d1</div>
</div>

这是我想要的输出:

<div class="a" >
  <div class="b">b1
    <div class="c">b1c1</div>
    <div class="d">b1d1</div>
    <div class="d">b1d2</div>
  </div>
  <div class="b">b2
    <div class="c">b2c1</div>
    <div class="d">b2d1</div>
    <div class="d">b2d2</div>
    <div class="d">b2d3</div>
  </div>
  <div class="b">b3
    <div class="c">b3c1</div>
    <div class="d">b3d1</div>
  </div>
</div>

这是我正在使用的xslt:

<?xml version="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="*"/>

 <!-- Identity template, copies everything as is -->
 <xsl:template match="@*|node()">
  <xsl:copy>
   <xsl:apply-templates select="@*|node()"/>
  </xsl:copy>
 </xsl:template>

 <!-- Override for target element -->
 <xsl:template match="div[@class='a']">
  <!-- Copy the element -->
  <xsl:copy>
   <!-- And everything inside it -->
   <xsl:copy-of select="@*|node()"/>
   <!-- Move nodes -->
   <xsl:apply-templates select="div[@class='c']"/>
   <xsl:apply-templates select="div[@class='d']"/>
  </xsl:copy>
 </xsl:template>

</xsl:stylesheet>

但它给了我错误的输出:

<div class="a">
  <div class="b">b1</div>
  <div class="c">b1c1</div>
  <div class="d">b1d1</div>
  <div class="d">b1d2</div>
  <div class="b">b2</div>
  <div class="c">b2c1</div>
  <div class="d">b2d1</div>
  <div class="d">b2d2</div>
  <div class="d">b2d3</div>
  <div class="b">b3</div>
  <div class="c">b3c1</div>
  <div class="d">b3d1</div>
  <div class="c">b1c1</div>
  <div class="c">b2c1</div>
  <div class="c">b3c1</div>
  <div class="d">b1d1</div>
  <div class="d">b1d2</div>
  <div class="d">b2d1</div>
  <div class="d">b2d2</div>
  <div class="d">b2d3</div>
  <div class="d">b3d1</div>
</div>

我理解为什么它会给我这个输出,但我找不到修改它并获得正确输出的方法。

提前谢谢。

PullingHair

1 个答案:

答案 0 :(得分:1)

看起来你正在通过前面的第一个“b”类对“c”和“d”类进行分组。要在XSLT 1.0中执行此操作,您可以定义一个键来捕获此分组。

<xsl:key name="b" match="div[@class!='b']" use="generate-id(preceding-sibling::div[@class='b'][1])" />

因此,不是选择模板中与“a”类匹配的所有子节点,而只选择“b”类

<xsl:apply-templates select="div[@class='b']" />

然后,在匹配“b”类的模板中,您可以使用该键来获取关联的“c”和“d”元素

<xsl:template match="div[@class='b']">
 <xsl:copy>
  <xsl:copy-of select="@*" />
  <xsl:apply-templates select="key('b', generate-id())" />
 </xsl:copy>
</xsl:template>

试试这个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="b" match="div[@class!='b']" use="generate-id(preceding-sibling::div[@class='b'][1])" />

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

 <xsl:template match="div[@class='a']">
  <xsl:copy>
   <xsl:apply-templates select="@*|div[@class='b']" />
  </xsl:copy>
 </xsl:template>

 <xsl:template match="div[@class='b']">
  <xsl:copy>
   <xsl:apply-templates select="@*|node()" />
   <xsl:apply-templates select="key('b', generate-id())" />
  </xsl:copy>
 </xsl:template>
</xsl:stylesheet>

在XSLT 2.0中,您可以使用xsl:for-each-group代替

<xsl:stylesheet version="2.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform">
 <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="div[@class='a']">
  <xsl:copy>
   <xsl:apply-templates select="@*" />
   <xsl:for-each-group select="div" group-starting-with="div[@class='b']">
     <xsl:copy>
      <xsl:apply-templates select="@*|node()" />
      <xsl:apply-templates select="current-group()[position() > 1]" />
     </xsl:copy>
    </xsl:for-each-group>
  </xsl:copy>
 </xsl:template>
</xsl:stylesheet>