问题
I have a series of nodes that are direct child nodes to a parent I want to loop over those nodes but have them wrapped in 'groups' of 4... I'm probably not wording this very clearly so this might help;
<span class="child01">@nodename</span>
<span class="child02">@nodename</span>
<span class="child03">@nodename</span>
<span class="child04">@nodename</span>
<span class="child05">@nodename</span>
<span class="child06">@nodename</span>
<span class="child07">@nodename</span>
<span class="child08">@nodename</span>
..
<span class="child32">@nodename</span>
<span class="child33">@nodename</span>
..and so on
Goal
<div class="group">
<span class="child01">@nodename</span>
<span class="child02">@nodename</span>
<span class="child03">@nodename</span>
<span class="child04">@nodename</span>
</div>
<div class="group">
<span class="child05">@nodename</span>
<span class="child06">@nodename</span>
<span class="child07">@nodename</span>
<span class="child08">@nodename</span>
</div>
<div class="group">
..
<span class="child32">@nodename</span>
</div>
<div class="group">
<span class="child33">@nodename</span>
..and so on
I have tried variations on this idea - wrapping the lot in the open and closing group tags and every fourth loop drop in a new close / open pair
<div class="group">
<xsl:for-each select="$currentPage/*">
<span>
<xsl:value-of select="@nodeName" />
</span>
<!--
=============================================================
After very 4th item
=============================================================
-->
<xsl:if test="position() mod 4 = 0">
<xsl:text></div><div class="page"></xsl:text>
</xsl:if>
</xsl:for-each>
</div>
But essentially it seems XSLT won't let me start with a closing unmatched tag The clkoset solution I ahve found so far is a 'fix' in jquery Wrapping a div around every three divs but I would rather not rely on javascript to format the page.
回答1:
This transformation:
<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:param name="pNumCols" select="3"/>
<xsl:template match="/*">
<xsl:apply-templates select="span[position() mod $pNumCols = 1]"/>
</xsl:template>
<xsl:template match="span">
<div>
<xsl:copy-of select=
".|following-sibling::span[not(position() > $pNumCols -1)]"/>
</div>
</xsl:template>
</xsl:stylesheet>
when applied on the provided XML document:
<t>
<span class="child01">@nodename</span>
<span class="child02">@nodename</span>
<span class="child03">@nodename</span>
<span class="child04">@nodename</span>
<span class="child05">@nodename</span>
<span class="child06">@nodename</span>
<span class="child07">@nodename</span>
<span class="child08">@nodename</span> ..
<span class="child32">@nodename</span>
<span class="child33">@nodename</span>
</t>
produces the wanted result:
<div>
<span class="child01">@nodename</span>
<span class="child02">@nodename</span>
<span class="child03">@nodename</span>
</div>
<div>
<span class="child04">@nodename</span>
<span class="child05">@nodename</span>
<span class="child06">@nodename</span>
</div>
<div>
<span class="child07">@nodename</span>
<span class="child08">@nodename</span>
<span class="child32">@nodename</span>
</div>
<div>
<span class="child33">@nodename</span>
</div>
回答2:
If like me you need to transform the source elements that are being divided by position, use xsl:for-each instead of xsl:copy:
<xsl:template match="span">
<ol>
<xsl:for-each select=".|following-sibling::span[not(position() > $pNumCols -1)]"/>
<li><xsl:value-of select="./text()"/></li>
</xsl:for-each>
</ol>
</xsl:template>
回答3:
Faced by the same problem, that is wanting to output
<div class="container">
<div class="row">
<div class="col">...</div>
<div class="col"/>...</div>
</div>
<div class="row">
...
</div>
</div>
from a CXML (Collection XML) file (http://gallery.clipflair.net/collection/activities.cxml - the data behind the PivotViewer display at http://gallery.clipflair.net/activity)
I coined up the following, based on other suggestions here, but using "mode" attribute of "template" and "apply-templates" XSL tags instead which make it cleaner I believe:
<?xml version="1.0" encoding="UTF-8"?>
<?altova_samplexml http://gallery.clipflair.net/collection/activities.cxml?>
<xsl:stylesheet
version="1.0"
xmlns:xsl="http://www.w3.org/1999/XSL/Transform"
xmlns:cxml="http://schemas.microsoft.com/collection/metadata/2009"
exclude-result-prefixes="cxml"
>
<xsl:output method="html" version="4.0" encoding="UTF-8" indent="yes"/>
<xsl:param name="COLUMNS" select="2"/>
<!-- ########################### -->
<xsl:template match="/">
<html xmlns="http://www.w3.org/1999/xhtml">
<head>
<meta http-equiv="Content-Type" content="text/html; charset=utf-8"/>
<title>ClipFlair Activities</title>
<link rel="stylesheet" type="text/css" href="style.css"/>
</head>
<body>
<xsl:apply-templates/>
</body>
</html>
</xsl:template>
<!-- ########################### -->
<xsl:template match="cxml:Collection">
<div class="container">
<xsl:apply-templates/>
</div>
</xsl:template>
<!-- ########################### -->
<xsl:template match="cxml:Items">
<xsl:apply-templates select="cxml:Item[position() mod $COLUMNS = 1]" mode="row"/>
</xsl:template>
<!-- ########################### -->
<xsl:template match="cxml:Item" mode="row">
<div class="row">
<div>----------</div>
<xsl:apply-templates select=".|following-sibling::cxml:Item[position() < $COLUMNS]" mode="col"/>
</div>
</xsl:template>
<xsl:template match="cxml:Item" mode="col">
<xsl:variable name="URL" select="@Href"/>
<xsl:variable name="FILENAME" select="cxml:Facets/cxml:Facet[@Name='Filename']/cxml:String/@Value"/>
<div class="col">
<xsl:value-of select="$FILENAME"/> --- <xsl:value-of select="$URL"/>
</div>
</xsl:template>
<!-- ########################### -->
<xsl:template match="*">
<xsl:apply-templates/>
</xsl:template>
<xsl:template match="text()|@*">
</xsl:template>
</xsl:stylesheet>
the output from the above when run in Altova XMLSpy tool (note that it uses altova_samplexml processor instruction to find the XML data) is:
2DaysInParis-OpenActivity-CapRev-FR-EN.clipflair --- http://studio.clipflair.net/?activity=2DaysInParis-OpenActivity-CapRev-FR-EN.clipflair
Abu_Dukhan-CapRev-A1-AR.clipflair --- http://studio.clipflair.net/?activity=Abu_Dukhan-CapRev-A1-AR.clipflair
----------
AFarewellToArms-RevCap-C2-EN.clipflair --- http://studio.clipflair.net/?activity=AFarewellToArms-RevCap-C2-EN.clipflair
agComhaireamhCountingRND.clipflair --- http://studio.clipflair.net/?activity=agComhaireamhCountingRND.clipflair
----------
Al-imtihan-CapRev-B1-AR.clipflair --- http://studio.clipflair.net/?activity=Al-imtihan-CapRev-B1-AR.clipflair
AlBar-Cap-B1-B2-IT.clipflair --- http://studio.clipflair.net/?activity=AlBar-Cap-B1-B2-IT.clipflair
...
来源:https://stackoverflow.com/questions/9908488/xslt-for-each-wrapping-every-nth-item-in-a-div