Reputation: 349
How would I avoid the last page-break element in the result:
<pages>
<page title="Manchuria"/>
<page-break/>
<page title="Zombie Librarian"/>
<page-break/>
<page title="Perfect the first time"/>
<page-break/>
</pages>
Given the following source xml:
<articles>
<article id="az401" title="The Long Goodbye" publishable="true" version="3">
<original>
<article id="aw301" version="1"/>
</original>
<edits>
<article id="az401" version="3"/>
<article id="pe814" version="2"/>
<article id="we453" version="4"/>
</edits>
</article>
<article id="yu475" title="Manchuria" publishable="true" version="4">
<original>
<article id="xc141" version="1"/>
</original>
<edits>
<article id="er111" version="2"/>
<article id="yu475" version="4"/>
<article id="iu931" version="3"/>
</edits>
</article>
<article id="nb741" title="Zombie Librarian" publishable="true" version="2">
<original>
<article id="nc441" version="1"/>
</original>
<edits>
<article id="nb741" version="2"/>
</edits>
</article>
<article id="ww555" title="Perfect the first time" publishable="true" version="1">
<original>
<article id="ww555" version="1"/>
</original>
<edits/>
</article>
<article id="kl922" title="Here we go again" publishable="true" version="1">
<original>
<article id="kl922" version="1"/>
</original>
<edits>
<article id="uy541" version="2"/>
</edits>
</article>
</articles>
And the following xslt code:
<xsl:stylesheet version="1.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform">
<xsl:output method="xml"/>
<xsl:key name="article-by-id" match="article" use="@id"/>
<xsl:template match="/">
<pages>
<xsl:apply-templates select="/articles/article[@publishable='true']" mode="subfilter"/>
</pages>
</xsl:template>
<xsl:template match="article" mode="subfilter">
<xsl:variable name="id_of_latest_edit">
<xsl:for-each select="edits/article">
<xsl:sort data-type="number" select="@version"/>
<xsl:if test="position()=last()"><xsl:value-of select="@id"/></xsl:if>
</xsl:for-each>
</xsl:variable>
<xsl:variable name="is_latest_edit" select="@id = key('article-by-id',$id_of_latest_edit)/@id"/>
<xsl:variable name="has_no_edits" select="not(edits/article)"/>
<xsl:if test="$is_latest_edit or $has_no_edits">
<xsl:apply-templates select="self::article" mode="layout">
<xsl:with-param name="is_last_page" select="position()=last()"/>
</xsl:apply-templates>
</xsl:if>
</xsl:template>
<xsl:template match="article" mode="layout">
<xsl:param name="is_last_page"/>
<page title="{@title}"/>
<xsl:if test="not($is_last_page)">
<page-break/>
</xsl:if>
</xsl:template>
</xsl:stylesheet>
notes
Upvotes: 0
Views: 510
Reputation: 117100
If it's not possible to filter the articles directly by using a predicate, then you can use a variable to hold the filtered set. Then using the position()
function on the result will work correctly:
XSLT 1.0 (+ EXSLT node-set() function)
<xsl:stylesheet version="1.0"
xmlns:xsl="http://www.w3.org/1999/XSL/Transform"
xmlns:exsl="http://exslt.org/common"
extension-element-prefixes="exsl">
<xsl:output method="xml" version="1.0" encoding="UTF-8" indent="yes"/>
<xsl:template match="/">
<pages>
<xsl:variable name="pages">
<xsl:apply-templates select="/articles/article[@publishable='true']" mode="subfilter"/>
</xsl:variable>
<xsl:apply-templates select="exsl:node-set($pages)/article"/>
</pages>
</xsl:template>
<xsl:template match="article" mode="subfilter">
<xsl:variable name="id_of_latest_edit">
<xsl:for-each select="edits/article">
<xsl:sort data-type="number" select="@version"/>
<xsl:if test="position()=last()">
<xsl:value-of select="@id"/>
</xsl:if>
</xsl:for-each>
</xsl:variable>
<xsl:if test="@id = $id_of_latest_edit or not(edits/article)">
<xsl:copy-of select="."/>
</xsl:if>
</xsl:template>
<xsl:template match="article">
<page title="{@title}"/>
<xsl:if test="position()!=last()">
<page-break/>
</xsl:if>
</xsl:template>
</xsl:stylesheet>
Upvotes: 1