Search code examples
xsltxslt-2.0

How to insert value substring-before last '(' after tokenize with ',' in XSLT


I am trying to insert value subring-before last '(' after tokenize start-with, '('. I have try both substring-before (e.g. <xsl:value-of select="concat(substring-before(current-grouping-key(), '('), .)"/>) '(' or replace function <p><xsl:value-of select="concat(replace(substring-before(current-grouping-key(), ','), '^([0-9]+)|(\(.*\))(\(([a-z0-9])\))', '$1$2'), .)"/></p>.
Input XML

<root>
<p>17200(b)(2), (4)–(6), (8), (12), (16), (20), and (21)</p>
<p>1(a), (b), (c)</p>
<p>2</p>
<p>2</p>
</root>

XSLT:

    <xsl:template match="root">
    <root>
        <xsl:for-each-group select="p" group-by=".">
            <xsl:choose>
                <xsl:when test="contains(current-grouping-key(), ', ')">
                    <xsl:for-each select="tokenize(current-grouping-key(), ', and |, ')">
                        <xsl:choose>
                            <xsl:when test="starts-with(., '(')">
                                <p><xsl:value-of select="concat(replace(substring-before(current-grouping-key(), ','), '^([0-9]+)|(\(.*\))(\(([a-z0-9])\))', '$1$2'), .)"/></p>
                                <!--<p><xsl:value-of select="concat(substring-before(current-grouping-key(), '('), .)"/></p>-->
                            </xsl:when>
                            <xsl:otherwise>
                                <p><xsl:value-of select="."/></p>
                            </xsl:otherwise>
                        </xsl:choose>
                    </xsl:for-each>
                </xsl:when>
                <xsl:otherwise>
                    <p><xsl:value-of select="current-grouping-key()"/></p>
                </xsl:otherwise>
            </xsl:choose>
        </xsl:for-each-group>
    </root>
</xsl:template>

Expected Output

   <root>
   <p>17200(b)(2)</p>
   <p>17200(b)(4)–(6)</p>
   <p>17200(b)(8)</p>
   <p>17200(b)(12)</p>
   <p>17200(b)(16)</p>
   <p>17200(b)(20)</p>
   <p>17200(b)(21)</p>
   <p>1(a)</p>
   <p>1(b)</p>
   <p>1(c)</p>
   <p>2</p>
</root>

CODE: https://xsltfiddle.liberty-development.net/3NSTbfj/31


Solution

  • I think the you seem to simply want to concatenate any characters in the first token before the last ( to the tokenized value:

    <xsl:template match="root">
        <root>
            <xsl:for-each-group select="p" group-by=".">
                <xsl:choose>
                    <xsl:when test="contains(current-grouping-key(), ', ')">
                        <xsl:variable name="tokens" select="tokenize(current-grouping-key(), ', and |, ')"/>
                        <xsl:for-each select="$tokens">
                            <p>
                                <xsl:value-of
                                  select="if (starts-with(., '('))
                                          then replace(head($tokens), '(.*)\(.*?\)$', '$1') || .
                                          else ."/>
                            </p>
    
                        </xsl:for-each>
                    </xsl:when>
                    <xsl:otherwise>
                        <p><xsl:value-of select="current-grouping-key()"/></p>
                    </xsl:otherwise>
                </xsl:choose>
            </xsl:for-each-group>
        </root>
    </xsl:template>
    

    https://xsltfiddle.liberty-development.net/3NSTbfj/33