开发者

XSLT How can I wrap each 3 elements by div?

I have some XML document with <item> elements, and i'd want to wrap each 3 of them in <div> If there is less than 3 elements, wrap them too.

<shop>
  <item></item>
  <item></item>
  <item></item>
  <item></item>
  <item></item>
  <item></item>
  .....
  <item></item>
</shop>

So result must be something like this

<div class="line">
  <item></item>
  <item></item>
  <item></item>
</div>
<div class="line">
  <item></item>
  <item></item>
开发者_运维技巧  <item></item>
</div>
....
<div class="line">
  <item></item>
  <item></item>
</div>


Probably your solution will be very similar to this:

HTML table with alternating row colors via XSL


The following stylesheet:

<xsl:stylesheet version="1.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform">
    <!--  the number of items to include in each group -->
    <xsl:variable name="group" select="3" />
    <xsl:template match="/">
        <xsl:apply-templates
            select="shop/item[position() mod $group = 1]" />
    </xsl:template>
    <xsl:template match="item" mode="inner">
        <!-- handle items appropriately here -->
        <item/>
    </xsl:template>
    <xsl:template match="item">
        <div class="line">
            <xsl:apply-templates
                select=".|following-sibling::item[position() &lt; $group]"
                mode="inner" />
        </div>
    </xsl:template>
</xsl:stylesheet>

Applied to this input:

<shop>
  <item></item>
  <item></item>
  <item></item>
  <item></item>
  <item></item>
  <item></item>
  <item></item>
  <item></item>
  <item></item>
  <item></item>
  <item></item>
  <item></item>
  <item></item>
  <item></item>
</shop>

Produces:

<div class="line">
    <item />
    <item />
    <item />
</div>
<div class="line">
    <item />
    <item />
    <item />
</div>
<div class="line">
    <item />
    <item />
    <item />
</div>
<div class="line">
    <item />
    <item />
    <item />
</div>
<div class="line">
    <item />
    <item />
</div>


  <xsl:for-each select"item">
    <xsl:choose>
      <xsl:when test="count(item) mod 3 = 0">
      </xsl:when>
      <xsl:otherwise>
      </xsl:otherwise>
    </xsl:choose>
  </xsl:foreach>

I haven't tried this, but important is the test in the foreach loop. count(item) mod 3 = 0 than you can react every third time.


A much simpler solution:

<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:template match="item[position() mod 3 = 1]">
  <div>
   <xsl:copy-of select=
    ".|following-sibling::*[not(position() > 2)]"/>
  </div>
 </xsl:template>
</xsl:stylesheet>

when applied on the provided XML document:

<shop>
    <item></item>
    <item></item>
    <item></item>
    <item></item>
    <item></item>
    <item></item>      
    <item></item>
</shop>

produces the wanted, correct result:

<div>
   <item/>
   <item/>
   <item/>
</div>
<div>
   <item/>
   <item/>
   <item/>
</div>
<div>
   <item/>
</div>

Update:

The OP has clarified that he needs a transformation that would process the XML document on this page. Everything should be copied as-is with the exception of any group of <item> elements that must be grouped by three and each group wrapped into a <div>.

Here is the code for this:

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

 <xsl:template match="node()[self::item and position() mod 3 = 1]">
   <div>
    <xsl:copy-of select=
    ".|following-sibling::*[not(position()>2)]"/>
   </div>
 </xsl:template>

 <xsl:template match=
  "node()[self::item and not(position() mod 3 = 1)]"/>

</xsl:stylesheet>
0

上一篇:

下一篇:

精彩评论

暂无评论...
验证码 换一张
取 消

最新问答

问答排行榜