简体   繁体   中英

Sequentially group / process contents with XSLT 2.0 / XSL-FO

Meta

  • XSLT 2.0
  • XSL-FO

I have to do two things:

1.) I want to apply templates for certain nodes (p) that do not follow after a (x).

So for the following example the only node that should be processed should be the first (p) .

XML

<p>example...</p>
<x>example...</x>
<p>example...</p>
<p>example...</p>
<p>example...</p>
<x>example...</x>
<p>example...</p>
<p>example...</p>

2.) I also want to process the contents for all (p) nodes as groups that follow after each (x).

So for the example above the contents that follow after each x should be put into the block element (s. below).

<xsl:template match="x">
    <fo:block>
        <!-- content from following (p) nodes until the next following (x) -->
    </fo:block>
</xsl:template>

Is there a simple way to do this with groups or intersections?

You have not shown any parent element but write a template for that parent:

<xsl:template match="div[x]">
    <fo:block>
      <xsl:for-each-group select="*" group-starting-with="x">
        <xsl:choose>
            <xsl:when test="self::x">
                <fo:block>
                    <xsl:copy-of select="current-group()[position() gt 1]"/>
                </fo:block>
            </xsl:when>
            <xsl:otherwise>
                <xsl:apply-templates select="current-group()"/>
            </xsl:otherwise>
        </xsl:choose>
      </xsl:for-each-group>
    </fo:block>
</xsl:template>

Sample is at http://xsltransform.net/gWvjQeW .

If you're doing the same thing for all groups of p and you really don't care about the x elements, you could do:

<xsl:template match="foo">
  <xsl:for-each-group select="p" group-adjacent="self::p">
    <fo:block>
      <xsl:apply-templates select="current-group()"/>
    </fo:block>
  </xsl:for-each-group>
</xsl:template>

but if you really did want to do something different for the first p (or multiple first p ):

<xsl:template match="foo">
  <xsl:for-each-group select="p" group-adjacent="self::p">
    <xsl:apply-templates select="."/>
  </xsl:for-each-group>
</xsl:template>

<xsl:template match="p[empty(preceding-sibling::x)]">
  <fo:block font-family="serif">
    <xsl:value-of select="current-group()"/>
  </fo:block>
</xsl:template>

<xsl:template match="p">
  <fo:block>
    <xsl:value-of select="current-group()"/>
  </fo:block>
</xsl:template>

since current-group() still works in other templates while you're within an iteration of the xsl:for-each-group .

Thanks to you I found a working solution.

I created a template for the parent container element (s. below):

<xsl:template match="container">
    <xsl:for-each group select="*" group-starting-with="x">
        <xsl:choose>
            <xsl:when test="self::x">
                <xsl:apply-templates select="current-group()[position() = 1]"/>
            </xsl:when>
            <xsl:otherwise
                <xsl:apply-templates select="current-group()"/>
            </xsl:otherwise>
        </xsl:choose>
    </xsl:for-each-group>
</xsl:template>

And additionally a template for the x element (s.below):

<xsl:template match="x">
    <fo:block>
        <xsl:apply-templates select="current-group()[position() gt 1]"/>
    </fo:block>
</xsl:template>

Result

Contents are processed in groups if preceding sibling is x; and also regulary if not but not as part of any x group.

These things are quiet hard to describe - Thank you for your patience!

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM