如何在XSLT 1.0中匹配并包装相同和相邻的节点?

时间:2014-04-24 16:12:26

标签: xslt xslt-1.0

我有一个看起来像这样的XML文件,我试图用div包装彼此相邻的“Para_bb”节点。

   <Para_a></Para_a>
   <Para_a></Para_a>
   <Para_bb></Para_bb>
   <Para_bb></Para_bb>
   <Para_bb></Para_bb>
   <Para_bb></Para_bb>
   <Para_a></Para_a>
   <Para_bb></Para_bb>
   <Para_bb></Para_bb>
   <Para_a></Para_a>
   <Para_a></Para_a>
   <Para_bb></Para_bb>

我怎样才能让它看起来像这样?

   <p></p>
   <p></p>
   <div class="blackBox">
      <Para_bb></Para_bb>
      <Para_bb></Para_bb>
      <Para_bb></Para_bb>
      <Para_bb></Para_bb>
   </div>
   <p></p>
   <div class="blackBox">
      <Para_bb></Para_bb>
      <Para_bb></Para_bb>
   </div>
   <p></p>
   <p></p>
   <div class="blackBox">
      <Para_bb></Para_bb>
   </div>

2 个答案:

答案 0 :(得分:4)

您可以按如下方式定义密钥:

<?xml version="1.0" encoding="UTF-8"?>
<xsl:stylesheet version="1.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform">

<xsl:output indent="yes"/>

<xsl:key name="group" match="Para_bb[preceding-sibling::*[1][self::Para_bb]]" use="generate-id(preceding-sibling::Para_bb[not(preceding-sibling::*[1][self::Para_bb])][1])"/>

<xsl:template match="Root">
  <body>
    <xsl:apply-templates/>
  </body>
</xsl:template>

<xsl:template match="Para_a">
  <p>
    <xsl:apply-templates/>
  </p>
</xsl:template>

<xsl:template match="Para_bb[preceding-sibling::*[1][self::Para_bb]]"/>

<xsl:template match="Para_bb[not(preceding-sibling::*[1][self::Para_bb])]">
  <div class="blackBox">
    <xsl:copy-of select=". | key('group', generate-id())"/>
  </div>
</xsl:template>

</xsl:stylesheet>

改变

<Root>
   <Para_a></Para_a>
   <Para_a></Para_a>
   <Para_bb>1</Para_bb>
   <Para_bb>2</Para_bb>
   <Para_bb>3</Para_bb>
   <Para_bb>4</Para_bb>
   <Para_a></Para_a>
   <Para_bb>5</Para_bb>
   <Para_bb>6</Para_bb>
   <Para_a></Para_a>
   <Para_a></Para_a>
   <Para_bb>7</Para_bb>
</Root>

<body>

   <p/>

   <p/>

   <div class="blackBox">
      <Para_bb>1</Para_bb>
      <Para_bb>2</Para_bb>
      <Para_bb>3</Para_bb>
      <Para_bb>4</Para_bb>
   </div>




   <p/>

   <div class="blackBox">
      <Para_bb>5</Para_bb>
      <Para_bb>6</Para_bb>
   </div>


   <p/>

   <p/>

   <div class="blackBox">
      <Para_bb>7</Para_bb>
   </div>

</body>

答案 1 :(得分:3)

在XSLT 1.0中执行此操作的一种方法是使模板与组中每个 Para_bb 元素的第一个匹配项匹配

<xsl:template match="Para_bb[not(preceding-sibling::*[1][self::Para_bb])]">

然后,您将在第一个元素

上调用指定模式的新模板
    <p>
        <xsl:apply-templates select="." mode="div" />
    </p>

然后,在匹配指定模式的 Para_bb 模板中,您将复制该元素,并选择下一个兄弟,但前提是它是另一个 Para_bb

<xsl:template match="Para_bb" mode="div">
    <xsl:call-template name="identity" />
    <xsl:apply-templates select="following-sibling::*[1][self::Para_bb]" mode="div"/>
</xsl:template>

(被调用的命名模板是标准身份模板)

试试这个XSLT

<xsl:stylesheet xmlns:xsl="http://www.w3.org/1999/XSL/Transform" version="1.0">
    <xsl:output method="xml" indent="yes"/>

    <xsl:template match="Para_bb[not(preceding-sibling::*[1][self::Para_bb])]">
        <div class="blackBox">
            <xsl:apply-templates select="." mode="div" />
        </div>
    </xsl:template>

    <xsl:template match="Para_bb" />

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

    <xsl:template match="Para_bb" mode="div">
        <xsl:call-template name="identity" />
        <xsl:apply-templates select="following-sibling::*[1][self::Para_bb]" mode="div"/>
    </xsl:template>

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