Search code examples
xslt-2.0xslt-grouping

Is it possible to group by full-stop in this XML?


I'd like to impose some structure on the following XML:

<phr>ΦP
    <i>το αθάνατο</i> ~.
    <i>ήπιε το αμίλητο</i> ~.
    <i>πίνω</i> ~ <i>στο όνομα κάποιου</i>, τον σέβομαι, τον εκτιμώ, αναγνωρίζοντας τα όσα του οφείλω.
    <i>λέω το</i> ~ <i>νεράκι</i>, για μεγάλη έλλειψη νερού.
</phr>

by grouping the contents of with the full-stop as a separator, as in:

<phr>
    <group>ΦP <i>το αθάνατο</i> ~.</group>
    <group>  <i>ήπιε το αμίλητο</i> ~.</group>
    <group>  <i>πίνω</i> ~ <i>στο όνομα κάποιου</i>, τον σέβομαι, τον εκτιμώ, αναγνωρίζοντας τα όσα <group>του οφείλω.</group>
    <group><i>λέω το</i> ~ <i>νεράκι</i>, για μεγάλη έλλειψη νερού.</group>
</phr>

Can anyone recommend some XSLT (2.0) for achieving this? I've tried for-each-group group-by 'text()[matches(.,'.')]', but that doesn't yield the desired result.

Many thanks!


Solution

  • This stylesheet should do what you need:

    <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">
    
      <!-- Identity template -->
      <xsl:template match="@*|node()">
        <xsl:copy>
          <xsl:apply-templates select="@*|node()"/>
        </xsl:copy>
      </xsl:template>
    
      <xsl:template match="phr">
        <xsl:copy>
          <xsl:for-each-group select="node()" group-ending-with="text()[contains(.,'.')]">
            <group>
              <xsl:apply-templates select="current-group()"/>
            </group>
          </xsl:for-each-group>
        </xsl:copy>
      </xsl:template>
    
    </xsl:stylesheet>