Search code examples
foreachtokenizexslt-3.0

for-each-group in combination with tokenize to collect all possible values from attribute


I’m once again over my head with creating the proper XSLT (3.0) for having a distinct list of persons mentioned in my text.

The XML looks like this:

<?xml version="1.0" encoding="UTF-8"?>
<p>Lorem ipsum dolor sit <rs ref="#1">Romeo</rs>, consetetur sadipscing elitr, <rs ref="#2"
        >Julia</rs> diam nonumy eirmod <rs ref="#2 #4">family</rs> invidunt ut labore et <other corresp="#3">Dolores</other></p>

I'm trying to get a list of all distinct values of either @ref or @corresp. Note that there can be two values in @ref or @corresp, so it needs to be tokenized.

The result could be like this:

<values>
    <a>#1</a>
    <a>#2</a>
    <a>#3</a>
    <a>#4</a>
</values>

In my real world usage i will use the received values to look up a list of persons in another file.

So far this is what i have:

<?xml version="1.0" encoding="UTF-8"?>
<xsl:stylesheet xmlns="http://www.w3.org/1999/xhtml"
    xmlns:xsl="http://www.w3.org/1999/XSL/Transform" version="3.0">
    <xsl:template match="p">
        <xsl:for-each-group select="descendant::*[self::rs or self::other]" group-by="@ref">
            <a>
                <xsl:copy-of select="@ref"/>
            </a>
        </xsl:for-each-group>
    </xsl:template>
</xsl:stylesheet>

I fail to integrate the tokenize(@ref, ' ') as well as that the values searched for are in either @ref or @corresp. What am I missing?


Solution

  • Something like this(edit):

    <?xml version="1.0" encoding="UTF-8"?>
    <xsl:stylesheet xmlns="http://www.w3.org/1999/xhtml"
      xmlns:xs="http://www.w3.org/2001/XMLSchema"
      xmlns:xsl="http://www.w3.org/1999/XSL/Transform" version="3.0">
    
      <xsl:template match="p">
        <xsl:variable name="numbers" as="xs:string*">
          <xsl:apply-templates select="rs/@ref|other/@corresp"/>
        </xsl:variable>
        <values>
          <xsl:for-each select="distinct-values($numbers)">
          <xsl:sort select="."/>
            <a>
              <xsl:value-of select="."/>
            </a>
          </xsl:for-each>
        </values>
      </xsl:template>
    
      <xsl:template match="@*">
        <xsl:sequence select="tokenize(.,'\s+')"/>
      </xsl:template>
    </xsl:stylesheet>