Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

xslt: assigning variables equal to one of two cases

I want to use the attribute @sourcename in the following way, as a convenience:

If @sourcename has a dot in it, the part before the first dot should be assigned to $srcgroup and the part after the first dot should be assigned to $srcword.

Otherwise $srcgroup should be set equal to @sourcename and $srcword should be the empty string.

In both cases I want to do the same things using $srcgroup and $srcword.

I tried this with the following fragment:

<xsl:choose>
   <xsl:when test="contains(@sourcename, '.')">     
     <xsl:variable name="srcgroup" select="substring-before(@sourcename, '.')"/> 
     <xsl:variable name="srcword" select="substring-after(@sourcename, '.')" />
   </xsl:when> 
   <xsl:otherwise>
     <xsl:variable name="srcgroup" select="@sourcename" />
     <xsl:variable name="srcword" />                     
   </xsl:otherwise>
</xsl:choose>

<foo group="{$srcgroup}" word="{$srcword}" />
<!-- there's some other more complicated users of $srcgroup and $srcword -->

The problem is I get an error (this is using JAXP in Java):

ERROR:  [my xsl file]: line 35: Variable or parameter 'srcgroup' is undefined.'
FATAL ERROR:  'Could not compile stylesheet'
Exception in thread "main" javax.xml.transform.TransformerConfigurationException: Could not compile stylesheet
    at com.sun.org.apache.xalan.internal.xsltc.trax.TransformerFactoryImpl.newTemplates(TransformerFactoryImpl.java:825)

If I understand this right, I'm guessing the variables only have the scope of the particular case in the <xsl:choose> block. Is there any way to get around this? I don't want to have to repeat my other code twice.


p.s. I found a workaround:

<xsl:variable name="srcgroup" select="substring-before(concat(@sourcename, '.'), '.')" /> 
<xsl:variable name="srcword" select="substring-after(@sourcename, '.')" />

but I still want to know how to solve my original question, for future reference.

like image 991
Jason S Avatar asked Jan 31 '12 15:01

Jason S


2 Answers

Just use (no conditionals necessary):

  <xsl:variable name="srcgroup" select=
  "substring-before(concat(@sourcename, '.'), '.')"/>

  <xsl:variable name="srcword" select=
  "substring-after(@sourcename, '.')"/>

Complete example:

<xsl:stylesheet version="1.0"
 xmlns:xsl="http://www.w3.org/1999/XSL/Transform">
 <xsl:output omit-xml-declaration="yes" indent="yes"/>

 <xsl:template match="x|y">
  <xsl:variable name="srcgroup" select=
  "substring-before(concat(@sourcename, '.'), '.')"/>

  <xsl:variable name="srcword" select=
  "substring-after(@sourcename, '.')"/>

  $srcgroup = "<xsl:value-of select="$srcgroup"/>"
  $srcword = "<xsl:value-of select="$srcword"/>"
 </xsl:template>
</xsl:stylesheet>

when applied on this XML document:

<t>
  <x sourcename="a.b.c"/>
  <y sourcename="noDots"/>
</t>

the wanted result is produced in both cases:

  $srcgroup = "a"
  $srcword = "b.c"

  $srcgroup = "noDots"
  $srcword = ""

Explanation: Unnecessary logic avoided by placing a sentinel.


Compare this to the much more verbose conditional syntax:

<xsl:stylesheet version="1.0"
 xmlns:xsl="http://www.w3.org/1999/XSL/Transform">
 <xsl:output omit-xml-declaration="yes" indent="yes"/>

 <xsl:template match="x|y">
  <xsl:variable name="srcgroup">
   <xsl:choose>
     <xsl:when test="contains(@sourcename, '.')">
      <xsl:value-of select="substring-before(@sourcename, '.')"/>
     </xsl:when>
     <xsl:otherwise>
      <xsl:value-of select="@sourcename"/>
     </xsl:otherwise>
   </xsl:choose>
  </xsl:variable>

  <xsl:variable name="srcword">
   <xsl:choose>
     <xsl:when test="contains(@sourcename, '.')">
      <xsl:value-of select="substring-after(@sourcename, '.')"/>
     </xsl:when>
     <xsl:otherwise/>
   </xsl:choose>
  </xsl:variable>

  $srcgroup = "<xsl:value-of select="$srcgroup"/>"
  $srcword = "<xsl:value-of select="$srcword"/>"
 </xsl:template>
</xsl:stylesheet>

When this more verbose transformation is applied on the same XML document (above), again the same correct result is produced:

  $srcgroup = "a"
  $srcword = "b.c"

  $srcgroup = "noDots"
  $srcword = ""
like image 122
Dimitre Novatchev Avatar answered Sep 28 '22 07:09

Dimitre Novatchev


It's more like this:

<xsl:variable name="srcgroup">
 <xsl:choose...>
  ...
 </xsl:choose>
</xsl:variable>
like image 36
Michael Krelin - hacker Avatar answered Sep 28 '22 07:09

Michael Krelin - hacker