xslt 2.0 group-starting-with by element contents

435 views Asked by At

I'm new to XSLT 2.0 and XPATH 2.0 and I'm struggling to grouping a list of contacts, my intent is to merge adjacent numbers that belongs to the the previous defined person (note the empty elements).

here my input XML

<rows>
  <row>
    <person>John</person>
    <tel>1111</tel>
  </row>
  <row>
    <person>George</person>
    <tel>2222</tel>
  </row>
  <row>
    <person></person>
    <tel>3333</tel>
  </row>
  <row>
    <person>Carter</person>
    <tel>4444</tel>
  </row>
  <row>
    <person>Mimmo</person>
    <tel>5555</tel>
  </row>
  <row>
    <person></person>
    <tel>6666</tel>
  </row>
  <row>
    <person></person>
    <tel>7777</tel>
  </row>
  <row>
    <person></person>
    <tel>8888</tel>
  </row>
</rows>

My desired output

<contacts>
  <contact>
        <person>John</person>
        <numbers>
          <tel>1111</tel>
        </numbers>
  </contact>
  <contact>
        <person>George</person>
        <numbers>
          <tel>2222</tel>
          <tel>3333</tel>
        </numbers>
  </contact>
  <contact>
        <person>Carter</person>
        <numbers>
          <tel>4444</tel>
        </numbers>
  </contact>
  <contact>
        <person>Mimmo</person>
        <numbers>
          <tel>5555</tel>
          <tel>6666</tel>
          <tel>7777</tel>
          <tel>8888</tel>
        </numbers>
  </contact>
</contacts>

My attempt to write an XSLT 2.0

<?xml version="1.0" encoding="UTF-8"?>
<xsl:stylesheet xmlns:xsl="http://www.w3.org/1999/XSL/Transform" version="2.0">
  <xsl:output method="xml" indent="yes"/>
  <xsl:template match="/">

    <xsl:for-each-group select="rows/row" group-starting-with="person[string-length(self) > 0]">
      <contact>
        <person>
          <xsl:value-of select="current-group()[1]/person"/>
        </person>
        <numbers>
        <xsl:for-each select="current-group()">
          <tel>
            <xsl:value-of select="tel"/>
          </tel>
        </xsl:for-each>
        </numbers>
      </contact>
    </xsl:for-each-group>
  </xsl:template>

</xsl:stylesheet>

and the output

<?xml version="1.0" encoding="UTF-8"?>
<contact>
   <person>John</person>
   <numbers>
      <tel>1111</tel>
      <tel>2222</tel>
      <tel>3333</tel>
      <tel>4444</tel>
      <tel>5555</tel>
      <tel>6666</tel>
      <tel>7777</tel>
      <tel>8888</tel>
   </numbers>
</contact>

I think that the problem is the grouping criteria, but I can't figure why. thanks

1

There are 1 answers

0
Martin Honnen On BEST ANSWER

You need to match on group-starting-with="row[normalize-space(person)]"

  <xsl:template match="/">
   <contacts>
    <xsl:for-each-group select="rows/row" group-starting-with="row[normalize-space(person)]">
      <contact>
        <xsl:copy-of select="person"/>
        <numbers>
          <xsl:copy-of select="current-group()/tel"/>
        </numbers>
      </contact>
    </xsl:for-each-group>
   </contacts>
  </xsl:template>