Home > Mobile >  Grouping the element not working properly
Grouping the element not working properly

Time:11-25

I want to group r element on the base of its attribute's values:

  1. If attribute values are same for current and following r elements then all should be wrap inside one r element.
  2. Need to remove all r element which is preceding by r which have same attributes and values.
  3. If empty sequences of same elements present then keep only one.

Problem i am facing is : - its remove last r you can refer as highlighted. 3 merge with above one

XML:

<text width="12240" height="15840" orient="">
<p style="pxpub">
    <r/>
    <r/>
</p>
<p type="itemlist" style="TRH2">
    <r pub="first"/>
    <r/>
    <r pub="first">1 </r>
    <r pub="first">2some text</r>
</p>
<p type="itemlist" style="TRH2">
    <r pub="first"/>
    <r pub="first"/>
    <r/>
    <r pub="a">1 some text</r>
    <r pub="a"> 2 merge with above one</r>
    <r pub="a"> 3 merge with above one</r>
    <r pub="first"/>
    <r pub="b"> 4 merge with above one</r>
    <r pub="b"> 5 merge with above one</r>
    <r pub="second"/>
</p>

XSLT:

<?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:strip-space elements="*"/>
    
    <xsl:output method="xhtml"/>
    
    <xsl:template match="@* | node()">
        <xsl:copy>
            <xsl:apply-templates select="@* | node()"/>
        </xsl:copy>
    </xsl:template>
    
    <xsl:template match="r">
        <xsl:variable name="selfattval" select="string-join(.//@*,'')"/>
        <xsl:choose>
            <xsl:when test="preceding-sibling::*[1][self::r[string-join(distinct-values(.//@*),'') = $selfattval]]/node()"/>
            <xsl:when test="$selfattval = preceding-sibling::*[1][self::r]/string-join(distinct-values(.//@*),'')"/>
            <xsl:otherwise>
                <r>
                    <xsl:apply-templates select="@* | node()"/>
                    <xsl:apply-templates select="following-sibling::*[1][self::r[string-join(distinct-values(.//@*),'') = $selfattval]]/node()"/>
                </r>
            </xsl:otherwise>
        </xsl:choose>
    </xsl:template>
</xsl:stylesheet>

Current Output:

<text width="12240" height="15840" orient="">
   <p style="pxpub">
      <r></r>
   </p>
   <p type="itemlist" style="TRH2">
      <r pub="first"></r>
      <r></r>
      <r pub="first">1 2some text</r>
   </p>
   <p type="itemlist" style="TRH2">
      <r pub="first"></r>
      <r></r>
      <r pub="a">1 some text 2 merge with above one</r>
      <r pub="first"></r>
      <r pub="b"> 4 merge with above one 5 merge with above one</r>
      <r pub="second"></r>
   </p>
</text>

Desire Output:

<text width="12240" height="15840" orient="">
<p style="pxpub">
    <r></r>
</p>
<p type="itemlist" style="TRH2">
    <r pub="first"></r>
    <r></r>
    <r pub="first">1 2some text</r>
</p>
<p type="itemlist" style="TRH2">
    <r pub="first"></r>
    <r></r>
    <r pub="a">1 some text 2 merge with above one  3 merge with above one</r>
    <r pub="first"></r>
    <r pub="b"> 4 merge with above one 5 merge with above one</r>
    <r pub="second"></r>
</p>

CodePudding user response:

It sounds like a task for for-each-group group-adjacent:

  <xsl:template match="*[r]">
    <xsl:copy>
      <xsl:apply-templates select="@*"/>
      <xsl:for-each-group select="r" group-adjacent="@*" composite="yes">
        <xsl:copy>
          <xsl:apply-templates select="@*, current-group()/node()"/>
        </xsl:copy>
      </xsl:for-each-group>
    </xsl:copy>
  </xsl:template>

This is XSLT 3 as supported since Saxon 9.8 and Saxon JS 2 but as long as you only have the pub attribute using

  <xsl:template match="*[r]">
    <xsl:copy>
      <xsl:apply-templates select="@*"/>
      <xsl:for-each-group select="r" group-adjacent="@*">
        <xsl:copy>
          <xsl:apply-templates select="@*, current-group()/node()"/>
        </xsl:copy>
      </xsl:for-each-group>
    </xsl:copy>
  </xsl:template>

should do the same in XSLT 2, or if you have multiple attributes and need them all to contribute to the grouping key, string-join e.g. group-adjacent="string-join(@*, '|')" them in XSLT 2.

  • Related