Re: [xsl] Best Way to Break Up Nested Structures Based On Inline Elements

Subject: Re: [xsl] Best Way to Break Up Nested Structures Based On Inline Elements
From: "Eliot Kimber ekimber@xxxxxxxxxxxx" <xsl-list-service@xxxxxxxxxxxxxxxxxxxxxx>
Date: Wed, 18 Apr 2018 21:19:36 -0000
Ken: I had forgotten about your PSMI. I'm coming back to FO after a long
absence.

Cheers,

E.

--
Eliot Kimber
http://contrext.com

o;?On 4/18/18, 4:01 PM, "G. Ken Holman g.ken.holman@xxxxxxxxx"
<xsl-list-service@xxxxxxxxxxxxxxxxxxxxxx> wrote:

    There are a number of users of my Page Sequence
    Master Interleave (PSMI) code for the rotated tables:

       https://cranesoftwrights.github.io/resources/psmi/index.htm

    Perhaps this has some ideas you can exploit.

    . . . . . . Ken

    At 2018-04-18 20:36 +0000, Eliot Kimber ekimber@xxxxxxxxxxxx wrote:

    >I definitely owe Gerrit the beverage of his
    >choice. I was able to make this code work with my details.
    >
    >While it's not obvious (at least not to me--I
    >still need to take some time to fully appreciate
    >how it works) it's definitely much more elegant
    >than the recursive approach I was thinking of.
    >
    >I will probably also need to use this technique
    >to handle the challenge of changing page
    >sequences to render long rotated tables or foldout pages.
    >
    >When generating FO it's much eaiser logically to
    >emit page sequence start markers and then come
    >back and allocate things to page sequences than
    >it is to try to work out the page sequence
    >mapping when there's not a simple mapping from
    >top-level elements to page sequences.
    >
    >Cheers,
    >
    >Eliot
    >--
    >Eliot Kimber
    >http://contrext.com
    >
    >C/B;B?On 4/18/18, 2:00 PM, "Imsieke, Gerrit, le-tex
    >gerrit.imsieke@xxxxxxxxx" <xsl-list-service@xxxxxxxxxxxxxxxxxxxxxx>
wrote:
    >
    >     Hold my beer.
    >
    >     <?xml version="1.0" encoding="UTF-8"?>
    >     <xsl:stylesheet xmlns:xsl="http://www.w3.org/1999/XSL/Transform";
    >        xmlns:xs="http://www.w3.org/2001/XMLSchema";
    >        xmlns:fo="http://www.w3.org/1999/XSL/Format";
    >        exclude-result-prefixes="xs"
    >        version="2.0">
    >
    >        <xsl:output indent="yes"/>
    >
    >        <xsl:template match="node() | @*" mode="#default split">
    >          <xsl:copy>
    >            <xsl:apply-templates select="@* | node()" mode="#current"/>
    >          </xsl:copy>
    >        </xsl:template>
    >
    >        <xsl:template match="fo:block[empty(ancestor::fo:block)]"
    >     mode="#default">
    >          <xsl:variable name="block-root" as="element(fo:block)"
select="."/>
    >          <xsl:for-each-group select="descendant::node()[empty(node())]"
    >     group-starting-with="two-column-start">
    >            <xsl:for-each-group select="current-group()"
    >     group-ending-with="two-column-end">
    >              <xsl:apply-templates select="$block-root" mode="split">
    >                <xsl:with-param name="restricted-to" as="node()*"
    >                  select="current-group()/ancestor-or-self::node()"
    >     tunnel="yes"/>
    >                <xsl:with-param name="two-col-start" as="xs:boolean"
    >     tunnel="yes"
    >                  select="exists(self::two-column-start)"/>
    >              </xsl:apply-templates>
    >            </xsl:for-each-group>
    >          </xsl:for-each-group>
    >        </xsl:template>
    >
    >        <xsl:template match="node()" mode="split" priority="1">
    >          <xsl:param name="restricted-to" tunnel="yes" as="node()+"/>
    >          <xsl:if test="exists(. intersect $restricted-to)">
    >            <xsl:next-match/>
    >          </xsl:if>
    >        </xsl:template>
    >
    >        <xsl:template
    > match="fo:block[empty(ancestor::fo:block)]" mode="split">
    >          <xsl:param name="restricted-to" tunnel="yes" as="node()*"/>
    >          <xsl:param name="two-col-start" tunnel="yes" as="xs:boolean"/>
    >          <xsl:copy>
    >            <xsl:apply-templates select="@*" mode="#current"/>
    >            <xsl:if test="$two-col-start">
    >              <xsl:attribute name="span" select="'none'"/>
    >            </xsl:if>
    >            <xsl:apply-templates mode="#current"/>
    >          </xsl:copy>
    >        </xsl:template>
    >
    >        <xsl:template match="two-column-start | two-column-end"
mode="split"/>
    >
    >     </xsl:stylesheet>
    >
    >
    >     On 18/04/2018 20:23, Eliot Kimber ekimber@xxxxxxxxxxxx wrote:
    >     > Gerrit,
    >     >
    >     > I don't immediately see how the code in
    > the referenced message works but it's simple enough to try in my
context.
    >     >
    >     > In my case the number of switches is
    > small relative to the total content, so it will
    > only be applied occasionally and infrequently.
    >     >
    >     > Cheers,
    >     >
    >     > E.
    >     >
    >     > --
    >     > Eliot Kimber
    >     > http://contrext.com
    >     >
    >     > C/B;B?On 4/18/18, 1:15 PM, "Imsieke, Gerrit,
    > le-tex gerrit.imsieke@xxxxxxxxx"
    > <xsl-list-service@xxxxxxxxxxxxxxxxxxxxxx> wrote:
    >     >
    >     >      Hi Eliot,
    >     >
    >     >      I think this can be tackled with
    > what I call "upward projection", see
    >     >      for ex. https://markmail.org/message/kmq2g4fidmw6cofz
    >     >
    >     >      You'd identify all leaf elements and
    > group them (maybe a combination of
    >     >      group-starting-with="two-colum-start" and
    >     >      group-ending-with="two-colum-end" is in order here).
    >     >
    >     >      Then for each group you transform
    > the top-level block in a certain mode,
    >     >      with a tunneled parameter. The
    > tunneled parameter contains the current
    >     >      group and its ancestors.
    >     >
    >     >      In the template that matches any
    > element in this mode, you check whether
    >     >      the tunneled parameter contains the current element. If so,
the
    >     >      next-match identity template will
    > apply, if not, nothing will be written
    >     >      to the result.
    >     >
    >     >      There's a special template in this mode that matches the
    >     >      two-column-start element. It will
    > create <fo:block span="none"> and then
    >     >      go on processing the children.
    >     >
    >     >      I'm not 100% sure whether this
    > works, but I have an intercontinental
    >     >      flight ahead of me. It will give me
    > some time to create working code,
    >     >      unless you're faster implementing
    > the suggested solution (or a better one).
    >     >
    >     >      I guess that the solution scales
    > with the number of splitting points
    >     >      times the number of leaves, so
    > performance may deteriorate for large
    >     >      documents with frequently changing column spans.
    >     >
    >     >      Gerrit
    >     >
    >     >      On 18/04/2018 19:45, Eliot Kimber ekimber@xxxxxxxxxxxx
wrote:
    >     >      > Using XSLT 2 with Saxon.
    >     >      >
    >     >      > In the context of generating
    > XSL-FO markup where there tree of fo:block
    > elements can be quite deep, I need to break the
    > blocks into a sequence of top-level blocks that
    > specify @span based on the presence of markers
    > anywhere in the heirarchy. This is to support
    > FOP's strict implementation of the FO spec,
    > which only allows specifying column spans on direct children of
fo:flow.
    >     >      >
    >     >      > In my processing I'm emitting
    > marker elements to signal the starts and ends
    > of areas that need to change the column spanning, e.g.:
    >     >      >
    >     >      > <fo:block span="all">
    >     >      >    <fo:block>
    >     >      >       <fo:block>
    >     >      >         <fo:block>
    >     >      >            <two-column-start/>
    >     >      >        </fo:block>
    >     >      >        ...
    >     >      >       <two-column-end/>
    >     >      >     </fo:block>
    >     >      >    <fo:block>...
    >     >      >    </fo:block>
    >     >      > </fo:block>
    >     >      >
    >     >      > Where the result needs to be:
    >     >      >
    >     >      > <fo:block span="all">
    >     >      >     <!-- Stuff before two-column start -->
    >     >      > </fo:block>
    >     >      > <fo:block span="none">
    >     >      >     <!-- Stuff up to <two-column-end/> marker -->
    >     >      > </fo:block>
    >     >      > <fo:block span="all">
    >     >      >    <!-- Stuff after <two-column-end> marker -->
    >     >      > </fo:block>
    >     >      >
    >     >      > There must be a general pattern
    > for solving this kind of transformation pattern
    > but I'm not seeing it or not remembering it.
    >     >      >
    >     >      > I can think of a recursive
    > algorithm to do it but is there a simpler or
    > more efficient approach? Conceptually it's a
    > for-each-group problem but the structure of the
    > content doesn't see to lend itself to grouping.
    >     >      >
    >     >      > Thanks,
    >     >      >
    >     >      > Eliot
    >     >      > --
    >     >      > Eliot Kimber
    >     >      > http://contrext.com
    >     >      >
    >     >      >
    >     >      >


    --
    Contact info, blog, articles, etc. http://www.CraneSoftwrights.com/s/ |
    Check our site for free XML, XSLT, XSL-FO and UBL developer resources |
    Streaming hands-on XSLT/XPath 2 training class @ US$45 (5 hours free) |

Current Thread