user19732805
user19732805

Reputation: 27

tokenize the string and select the specific values

I am working on XSLT2 script where the variable contains following text:

<xsl:variable name="urlparams" select="'color=red;rating=5;page=8;product=xyz'"/>

I want to construct below url. The equal to (=) values are dynamic, so next time it may change. For example (color=blue or product=abc).

<a href="www.google.com/?color=red&product=xyz"/>

Here is my xslt but it is not working :(

<xsl:template match="/">
        <xsl:variable name="urlparams" select="'color=red;rating=5;page=8;product=xyz'"/>
        <xsl:value-of select="'www.google.com/?'"/>
        <xsl:for-each select="tokenize($urlparams, ';')">
            <xsl:if test=". = 'color'">
                <xsl:value-of select="."/><xsl:text>&amp;</xsl:text>
            </xsl:if>
            <xsl:if test=". = 'product'">
                <xsl:value-of select="."/>
            </xsl:if>
        </xsl:for-each>

 </xsl:template>

Upvotes: 2

Views: 402

Answers (1)

Dimitre Novatchev
Dimitre Novatchev

Reputation: 243449

Here is a pure XPath 2.0 expression whose evaluation produces the wanted result:

      for $host in 'www.google.com/',
          $qParams in 'color=red;rating=5;page=8;product=xyz',
          $qString in string-join(tokenize($qParams, ';')
                                  [starts-with(., 'color=') or starts-with(., 'product=')],
                                 '&amp;')
         return
           concat($host, '?'[$qString], $qString)

XSLT 2.0 based validation:

<xsl:stylesheet version="2.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform">
 <xsl:output method="html"/>

  <xsl:template match="/">
    <xsl:variable name="vUrl" select=
     "for $host in 'www.google.com/',
            $qParams in 'color=red;rating=5;page=8;product=xyz',
            $qString in string-join(tokenize($qParams, ';')
                         [starts-with(., 'color=') or starts-with(., 'product=')], 
                                  '&amp;')
         return
           concat($host, '?'[$qString], $qString)
     "/>
     
     <a href="{$vUrl}"/>
  </xsl:template>
</xsl:stylesheet>

When this transformation is applied on any source XML document (not used), it evaluates the XPath expression and inserts the result as AVT as the value of the href attribute of the wanted <a> element, producing the wanted, correct result:

<a href="www.google.com/?color=red&amp;product=xyz"></a>


Part II

One can even avoid hard-coding the wanted QS parameter -names, by presenting them within a parameter, like this:

for $host in 'www.google.com/',
    $wantedPNames in '|color|product|',
    $qParams in 'color=red;rating=5;page=8;product=xyz',
    $qString in string-join(tokenize($qParams, ';')
                         [contains($wantedPNames, concat('|',tokenize(., '=')[1], '|'))],
                           '&amp;')
   return
     concat($host, '?'[$qString], $qString)

Evaluating the XPath expression above, again produces the wanted, correct result:

www.google.com/?color=red&product=xyz

Here is again the XSLT 2.0 - based verification:

<xsl:stylesheet version="2.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform">
 <xsl:output method="html"/>
 <xsl:param name="wantedPNames" select="'|color|product|'"/>

  <xsl:template match="/">
    <xsl:variable name="vUrl" select=
     "for $host in 'www.google.com/',
          $qParams in 'color=red;rating=5;page=8;product=xyz',
          $qString in string-join(tokenize($qParams, ';')
                         [contains($wantedPNames, concat('|',tokenize(., '=')[1], '|'))],
                                 '&amp;')
   return
     concat($host, '?'[$qString], $qString)
     "/>
     
     <a href="{$vUrl}"/>
  </xsl:template>
</xsl:stylesheet>

Again the same correct and wanted result is produced:

<a href="www.google.com/?color=red&amp;product=xyz"></a>


The OP asked additionally: "Question: If there is only 'color' param then there is no need of '&' at the end. How to conditionalize that so it wont be added in url? "

Answer: This same solution works correctly in such cases:

<xsl:stylesheet version="2.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform">
 <xsl:output method="html"/>
 <xsl:param name="wantedPNames" select="'|color|'"/>

  <xsl:template match="/">
    <xsl:variable name="vUrl" select=
     "for $host in 'www.google.com/',
          $qParams in 'color=red;rating=5;page=8;product=xyz',
          $qString in string-join(tokenize($qParams, ';')
                         [contains($wantedPNames, concat('|',tokenize(., '=')[1], '|'))],
                                 '&amp;')
   return
     concat($host, '?'[$qString], $qString)
     "/>

     <a href="{$vUrl}"/>
  </xsl:template>
</xsl:stylesheet>

Again the correct result is produced:

<a href="www.google.com/?color=red"></a>

Even if no parameters are passed, the result of this same solution will still be correct:

<xsl:stylesheet version="2.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform">
 <xsl:output method="html"/>
 <xsl:param name="wantedPNames" select="'||'"/>

  <xsl:template match="/">
    <xsl:variable name="vUrl" select=
     "for $host in 'www.google.com/',
          $qParams in 'color=red;rating=5;page=8;product=xyz',
          $qString in string-join(tokenize($qParams, ';')
                         [contains($wantedPNames, concat('|',tokenize(., '=')[1], '|'))],
                                 '&amp;')
   return
     concat($host, '?'[$qString], $qString)
     "/>

     <a href="{$vUrl}"/>
  </xsl:template>
</xsl:stylesheet>

Again the correct result:

<a href="www.google.com/"></a>

Upvotes: 1

Related Questions