Strugling with variable occurrence

Here should go questions about transforming XML with XSLT and FOP.
ehermans
Posts: 1
Joined: Thu Jun 13, 2019 11:11 pm

Strugling with variable occurrence

Post by ehermans » Thu Jun 13, 2019 11:20 pm

Hello i've the following source xml:

<A>
<B>
<C>c1</C>
<D>d1</D>
<D>d2</D>
<D>d3</D>
<C>c2</C>
<D>d1</D>
<D>d2</D>
<C>c3</C>
<D>d1</D>
<D>d2</D>
<D>d3</D>
</B>
</A>

and my output xml should be:
<A>
<B>
<C>c1</C>
<D>d1</D>
<D>d2</D>
<D>d3</D>
</B>
<B>
<C>c2</C>
<D>d1</D>
<D>d2</D>
</B>
<B>
<C>c3</C>
<D>d1</D>
<D>d2</D>
<D>d3</D>
</B>
</A>

I struggle how to achieve this... recurring template ?? or something??
Only can use xslt 1.0

Any clue?
thanks in advance.

Martin Honnen
Posts: 54
Joined: Tue Aug 19, 2014 12:04 pm

Re: Strugling with variable occurrence

Post by Martin Honnen » Fri Jun 14, 2019 11:35 am

As you are posting in the oXygen forum, you should have access to use Saxon 9 as an XSLT 2 or 3 processor and then it becomes a text book approach for
for-each-group group-starting-with

Code: Select all

<?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"
	exclude-result-prefixes="#all"
	version="3.0">

  <xsl:mode on-no-match="shallow-copy"/>

  <xsl:output method="xml" indent="yes"/>

  <xsl:template match="B">
      <xsl:for-each-group select="*" group-starting-with="C">
          <xsl:copy select="..">
              <xsl:apply-templates select="current-group()"/>
          </xsl:copy>
      </xsl:for-each-group>
  </xsl:template>
  
</xsl:stylesheet>
https://xsltfiddle.liberty-development.net/ncdD7mZ/1

If you are really stuck with an XSLT 1 processor then using a key is one way:

Code: Select all

<?xml version="1.0" encoding="UTF-8"?>
<xsl:stylesheet xmlns:xsl="http://www.w3.org/1999/XSL/Transform"
	version="1.0">

  <xsl:output method="xml" indent="yes"/>
  <xsl:strip-space elements="*"/>
  
  <xsl:key name="starting-with-c"
    match="B/*[not(self::C)]"
    use="generate-id(preceding-sibling::C[1])"/>

  <xsl:template match="@* | node()">
      <xsl:copy>
          <xsl:apply-templates select="@* | node()"/>
      </xsl:copy>
  </xsl:template>
  
  <xsl:template match="B">
      <xsl:apply-templates select="C"/>
  </xsl:template>
  
  <xsl:template match="C">
      <B>
          <xsl:copy-of select=". | key('starting-with-c', generate-id())"/>
      </B>
  </xsl:template>
  
</xsl:stylesheet>

https://xsltfiddle.liberty-development.net/ncdD7mZ/2

Post Reply