Lokesh
Lokesh

Reputation: 129

XSLT execute list of xpaths stored in a variable

I'm trying to execute a set of given xpaths that are stored in a variable using XSLT 1.0. While accessing the list of xpaths using for-each inside the template, the context changes and thus unable to extract any xpath value from the original xml. It simply returns blank value.

Input xml:

<catalog>
    <book id="bk101">
        <author>Gambardella Matthew</author>
        <title>XML Developer's Guide</title>
        <genre>Computer</genre>
        <price>44.95</price>
        <publish_date>2000-10-01</publish_date>
    </book>
    <book id="bk102">
        <author>Ralls Kim</author>
        <title>Midnight Rain</title>
        <genre>Fantasy</genre>
        <price>5.95</price>
    </book>
</catalog>

XSLT I tried:

<xsl:stylesheet xmlns:xsl="http://www.w3.org/1999/XSL/Transform" xmlns:dyn="http://exslt.org/dynamic" xmlns:exsl="http://exslt.org/common" version="1.0" exclude-result-prefixes="dyn exsl">
  <xsl:variable name="newLine" select="'&#xA;'" />
  <xsl:variable name="comma" select="','" />
  <xsl:variable name="details">
    <xpaths>
      <xpath>/catalog/book/author</xpath>
      <xpath>/catalog/book/title</xpath>
      <xpath>/catalog/book/genre</xpath>
      <xpath>/catalog/book/price</xpath>
      <xpath>/catalog/book/publish_date</xpath>
    </xpaths>
  </xsl:variable>
  <xsl:template match="/">
    <xsl:apply-templates select="*" mode="extract" />
  </xsl:template>
  <xsl:template match="book" mode="extract">
    <xsl:if test="position() !=1">
      <xsl:value-of select="$newLine" />
    </xsl:if>
    <xsl:for-each select="exsl:node-set($details)/xpaths/xpath">
      <xsl:if test="position() ! =1" />
      <xsl:value-of select="$comma" />
      <xsl:variable name="this" select="." />
      <xsl:value-of select="dyn:evaluate($this)" />
    </xsl:for-each>
  </xsl:template>
</xsl:stylesheet>

The output I'm expecting is:

Gambardella Matthew,XML Developer's Guide,Computer,44.95,2000-10-01
Ralls Kim,Midnight Rain,Fantasy,5.95,,

The output above xslt produces:

,,,,,
,,,,,

Can someone give a clue on the required XSLT 1.0 please? Thank you in advance.

Upvotes: 0

Views: 523

Answers (1)

Martin Honnen
Martin Honnen

Reputation: 167696

I don't think the absolute XPath expressions you have used make sense in the context of a book element, you would need to use relative paths. Then you can change the context to the book as follows:

<xsl:variable name="details">
    <xpaths>
        <xpath>author</xpath>
        <xpath>title</xpath>
        <xpath>genre</xpath>
        <xpath>price</xpath>
        <xpath>publish_date</xpath>
    </xpaths>
</xsl:variable>
<xsl:template match="/">
    <xsl:apply-templates select="*" mode="extract" />
</xsl:template>
<xsl:template match="book" mode="extract">
    <xsl:if test="position() !=1">
        <xsl:value-of select="$newLine" />
    </xsl:if>
    <xsl:variable name="book" select="."/>
    <xsl:for-each select="exsl:node-set($details)/xpaths/xpath">
        <xsl:if test="position() != 1">
            <xsl:value-of select="$comma" />
        </xsl:if>
        <xsl:variable name="path" select="." />
        <xsl:for-each select="$book"><xsl:value-of select="dyn:evaluate($path)" /></xsl:for-each>
    </xsl:for-each>
</xsl:template>

Obviously if you simply use $book/*[local-name() = $path] you would get it to work without using the usually unsupported dyn:evaluate.

Upvotes: 1

Related Questions