xsl-list
[Top] [All Lists]

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

2018-04-18 14:00:44
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(_at_)contrext(_dot_)com 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
On 4/18/18, 1:15 PM, "Imsieke, Gerrit, le-tex gerrit(_dot_)imsieke(_at_)le-tex(_dot_)de" <xsl-list-service(_at_)lists(_dot_)mulberrytech(_dot_)com> 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(_at_)contrext(_dot_)com 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
     >
     >
     >
--
     Gerrit Imsieke
     Geschäftsführer / Managing Director
     le-tex publishing services GmbH
     Weissenfelser Str. 84, 04229 Leipzig, Germany
     Phone +49 341 355356 110, Fax +49 341 355356 510
     gerrit(_dot_)imsieke(_at_)le-tex(_dot_)de, http://www.le-tex.de
Registergericht / Commercial Register: Amtsgericht Leipzig
     Registernummer / Registration Number: HRB 24930
Geschäftsführer / Managing Directors:
     Gerrit Imsieke, Svea Jelonek, Thomas Schmidt


--
Gerrit Imsieke
Geschäftsführer / Managing Director
le-tex publishing services GmbH
Weissenfelser Str. 84, 04229 Leipzig, Germany
Phone +49 341 355356 110, Fax +49 341 355356 510
gerrit(_dot_)imsieke(_at_)le-tex(_dot_)de, http://www.le-tex.de

Registergericht / Commercial Register: Amtsgericht Leipzig
Registernummer / Registration Number: HRB 24930

Geschäftsführer / Managing Directors:
Gerrit Imsieke, Svea Jelonek, Thomas Schmidt
--~----------------------------------------------------------------
XSL-List info and archive: http://www.mulberrytech.com/xsl/xsl-list
EasyUnsubscribe: http://lists.mulberrytech.com/unsub/xsl-list/1167547
or by email: xsl-list-unsub(_at_)lists(_dot_)mulberrytech(_dot_)com
--~--

<Prev in Thread] Current Thread [Next in Thread>