Librak
Librak

Reputation: 141

Get a single value from multiple attribute values of XML using xslt

I have a xml and I want the attribute which is defined in the "title" using XSL file. I want to retrieve the value of style both "abc" and "cdf" values

<catalog>
    <cd>
       <title style="abc:true;cdf:false"  att2="false">Empire Burlesque</title>
        <artist>Bob Dylan</artist>
        <country>USA</country>
        <company>Columbia</company>
        <price>10.90</price>
        <year>1985</year>
    </cd>
</catalog>

i tried this

 <td><xsl:value-of select="substring-before(substring-after(@style,'abc:'),';')"/></td>

Upvotes: 2

Views: 2212

Answers (3)

Dimitre Novatchev
Dimitre Novatchev

Reputation: 243479

This is a generic transformation that allows a string containing indefinite number of name-value pairs to be processed:

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

 <xsl:template match="/">
  <xsl:variable name="vStyle" select="/*/*/title/@style"/>

  The value for 'abc' is : <xsl:text/>
  <xsl:call-template name="getValueOfName">
   <xsl:with-param name="pText" select="$vStyle"/>
   <xsl:with-param name="pName" select="'abc'"/>
  </xsl:call-template>

  The value for 'cdf' is : <xsl:text/>
  <xsl:call-template name="getValueOfName">
   <xsl:with-param name="pText" select="$vStyle"/>
   <xsl:with-param name="pName" select="'cdf'"/>
  </xsl:call-template>


  The value for 'xyz' is : <xsl:text/>
  <xsl:call-template name="getValueOfName">
   <xsl:with-param name="pText" select="$vStyle"/>
   <xsl:with-param name="pName" select="'xyz'"/>
  </xsl:call-template>
 </xsl:template>

 <xsl:template name="getValueOfName">
  <xsl:param name="pText"/>
  <xsl:param name="pName"/>

  <xsl:choose>
      <xsl:when test="not(string-length($pText) > 0)"
        >***Not Found***</xsl:when>
      <xsl:otherwise>
        <xsl:variable name="vPair" select=
         "substring-before(concat($pText, ';'), ';')"/>

         <xsl:choose>
           <xsl:when test=
           "$pName = substring-before(concat($vPair, ':'), ':')">

             <xsl:value-of select="substring-after($vPair, ':')"/>
           </xsl:when>
           <xsl:otherwise>
             <xsl:call-template name="getValueOfName">
               <xsl:with-param name="pText" select=
                  "substring-after($pText, ';')"/>
               <xsl:with-param name="pName" select="$pName"/>
             </xsl:call-template>
           </xsl:otherwise>
         </xsl:choose>
      </xsl:otherwise>
  </xsl:choose>
 </xsl:template>
</xsl:stylesheet>

when applied on the provided XML document:

<catalog>
    <cd>
        <title style="abc:true;cdf:false"  att2="false">Empire Burlesque</title>
        <artist>Bob Dylan</artist>
        <country>USA</country>
        <company>Columbia</company>
        <price>10.90</price>
        <year>1985</year>
    </cd>
</catalog>

produces the wanted result:

  The value for 'abc' is : true

  The value for 'cdf' is : false


  The value for 'xyz' is : ***Not Found***

Explanation:

The getValueOfName template is a generic template that finds the name-value pair containing the specified pName and then outputs the value -- or if this name isn't found at all, the string ***Not Found*** is output.

The template first gets the first name-value pair from the string and processes it. In case the pName isn't present in the current name-value pair, then the template calls itself recursively on the text following the current name-value-pair.

Upvotes: 3

Andy
Andy

Reputation: 9048

I suspect your problem relates to the way you are referencing the @style attribute.

If you are using XPath 2.0, you can use a function call (e.g. substring-after, substring-before) to the right of the / operator. So this will work:

/catalog/cd/title/substring-before(substring-after(@style,'abc:'),';')

In XPath 1.0, you cannot do this, the thing to the right of each / must be an axis step (not a function call), so you would have to use:

substring-before(substring-after(/catalog/cd/title/@style,'abc:'),';') 

Upvotes: 2

rene
rene

Reputation: 42453

I think you're close:

  <!-- abc -->
  <xsl:value-of 
       select="substring-after(
               substring-before(/catalog/cd/title/@style,';'),'abc:')"/>
  <!-- cdf -->
 <xsl:value-of 
      select="substring-after(
              substring-after(/catalog/cd/title/@style,';'),'cdf:')"/>

Upvotes: 1

Related Questions