Frage

I have an XML file that look like this and I'm trying to wrap "Para_bb" node that are adjacent to each other with a div.

   <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>

How can I make it look like this?

   <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>
War es hilfreich?

Lösung

You can define a key as follows:

<?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>

That transforms

<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>

into

<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>

Andere Tipps

One way to do this in XSLT 1.0 is to have a template that matches the first occurrence of each Para_bb element in a group

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

Then you would call a new template, with a mode specified, just on this first element

    <p>
        <xsl:apply-templates select="." mode="div" />
    </p>

Then, in the template matching Para_bb with the mode specified, you would copy the element, and select the next sibling, but only if it is another 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>

(Where the named template being called is the standard identity template)

Try this 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>
Lizenziert unter: CC-BY-SA mit Zuschreibung
Nicht verbunden mit StackOverflow
scroll top