Subject: Re: [xsl] XSLT2: Grouping mixed content between opening and closing marker elements From: "Martin Honnen martin.honnen@xxxxxx" <xsl-list-service@xxxxxxxxxxxxxxxxxxxxxx> Date: Sat, 15 Aug 2020 13:01:00 -0000 |
Am 15.08.2020 um 12:19 schrieb Keith Burt keithburt66@xxxxxxxxx:
In my simplified example, I have self closing 'e' elements that have a tag attribute that denotes the start and end points of where style (in this case bold and italic) shouldB be applied. I want to group the content within the start and end markers, and create a wrapper element based on the tag attribute.
That sounds like a grouping task for a nested B for-each-group group-starting-with="e" B B B for-each-group group-ending-with="e" with some more precise conditions.
Or in XSLT 3 you could think of xsl:iterate or fold-left.
Looking at it closer it seems you could use the for-each-group within an iterate, to handle the nesting of e.g. <e tag="b">...<e tag="i">...<e tag="/i">...<e tag="/i>".
<?xml version="1.0" encoding="utf-8"?> <xsl:stylesheet xmlns:xsl="http://www.w3.org/1999/XSL/Transform" version="3.0" xmlns:xs="http://www.w3.org/2001/XMLSchema" exclude-result-prefixes="#all" xmlns:mf="http://example.com/mf" expand-text="yes">
<xsl:function name="mf:wrap" as="node()*"> <xsl:param name="nodes" as="node()*"/> <xsl:param name="tag" as="xs:string"/> <xsl:for-each-group select="$nodes" group-starting-with="e[@tag = $tag]"> <xsl:choose> <xsl:when test="not(self::e[@tag = $tag])"> <xsl:apply-templates select="current-group()"/> </xsl:when> <xsl:otherwise> <xsl:for-each-group select="tail(current-group())" group-ending-with="e[@tag = '/' || $tag]"> <xsl:choose> <xsl:when test="current-group()[last()][self::e][@tag = '/' || $tag]"> <xsl:element name="{$tag}"> <xsl:apply-templates select="current-group()[position() lt last()]"/> </xsl:element> </xsl:when> <xsl:otherwise> <xsl:apply-templates select="current-group()"/> </xsl:otherwise> </xsl:choose> </xsl:for-each-group> </xsl:otherwise> </xsl:choose> </xsl:for-each-group> </xsl:function>
<xsl:function name="mf:wrap" as="node()*"> <xsl:param name="nodes" as="node()*"/> <xsl:iterate select="distinct-values($nodes[self::e/@tag[not(starts-with(., '/'))]]/@tag)"> <xsl:param name="nodes" as="node()*" select="$nodes"/> <xsl:on-completion> <xsl:sequence select="$nodes"/> </xsl:on-completion> <xsl:next-iteration> <xsl:with-param name="nodes" select="mf:wrap($nodes, .)"/> </xsl:next-iteration> </xsl:iterate> </xsl:function>
<xsl:template match="*[e[@tag]]"> <xsl:copy> <xsl:apply-templates select="@*"/> <xsl:sequence select="mf:wrap(node())"/> </xsl:copy> </xsl:template>
That's XSLT 3 obviously, so I am not sure whether it helps as your original question only mentioned XSLT 2. However, since 2017, we have XSLT 3 and Saxon 9.8 and later or Altova XML 2017 R3 and later should support XSLT 3.
Current Thread |
---|
|
<- Previous | Index | Next -> |
---|---|---|
Re: [xsl] XSLT2: Grouping mixed con, Martin Honnen martin | Thread | Re: [xsl] XSLT2: Grouping mixed con, Keith Burt keithburt |
Re: [xsl] XSLT2: Grouping mixed con, Martin Honnen martin | Date | Re: [xsl] problem with transforming, Wolfhart Totschnig w |
Month |