Maria
Maria

Reputation: 47

xsl moving the following sibling to the current tag

I need to move the following-siblings that are just after the current element inside the current element. I do not understand why what I am doing is not working, could you please help me understand why?

I have this XML input:

<book>
<prelim>
    <introd></introd>
    <introd></introd>
    <bibl></bibl>
    <bibl></bibl>
</prelim>

I need to have this output:

<book>
<prelim>
    <introd></introd>
    <introd>
        <bibl></bibl>
        <bibl></bibl>
    </introd>
</prelim>

It tried this :

<?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="xs"
version="2.0">
<xsl:template match="*"><xsl:element name="{local-name()}"><xsl:apply-templates/></xsl:element>
</xsl:template>
<xsl:template match="introd">
    <introd>
    <xsl:apply-templates/>
    <xsl:variable name="i"><xsl:value-of select="following-sibling::bibl/position()"/></xsl:variable>
    <xsl:if test="following-sibling::*[$i]=following-sibling::bibl[$i]">
            <xsl:apply-templates select="following-sibling::bibl[following-sibling::*[$i]=following-sibling::bibl[$1]]"></xsl:apply-templates>
    </xsl:if>
    </introd>
</xsl:template>
</xsl:stylesheet>

Thank you! Maria

Upvotes: 0

Views: 81

Answers (2)

Martin Honnen
Martin Honnen

Reputation: 167571

I would suggest to match on prelim and then use xsl:for-each-group select="*" group-starting-with="introd":

  <xsl:template match="prelim">
      <xsl:copy>
          <xsl:for-each-group select="*" group-starting-with="introd">
              <xsl:copy>
                  <xsl:apply-templates select="node(), tail(current-group())"/>
              </xsl:copy>
          </xsl:for-each-group>
      </xsl:copy>
  </xsl:template>

The rest can be handled by the identity transformation, declarable with xsl:mode in XSLT 3 (https://xsltfiddle.liberty-development.net/naZYrpT) or spelled out as a template in XSLT 2. tail is not available in XSLT 2 but you can use subsequence(current-group(), 2) instead.

Upvotes: 1

Maria
Maria

Reputation: 47

Thank you, Martin Honnen. I resolved this the following way:

<?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="xs"
version="2.0">
<xsl:template match="*"><xsl:element name="{local-name()}"><xsl:apply-templates/></xsl:element></xsl:template>
   <xsl:template match="introd">
    <introd><xsl:apply-templates></xsl:apply-templates>
        <xsl:if test="following-sibling::*[1]=following-sibling::bibl[1]"><xsl:for-each-group select="parent::prelim/bibl" group-starting-with="introd"><xsl:for-each select="current-group()">
            <xsl:copy-of select="."/>
        </xsl:for-each></xsl:for-each-group></xsl:if></introd>
</xsl:template>
<xsl:template match="bibl"></xsl:template>

</xsl:stylesheet>

Upvotes: 0

Related Questions