This is the mail archive of the xsl-list@mulberrytech.com mailing list .


Index Nav: [Date Index] [Subject Index] [Author Index] [Thread Index]
Message Nav: [Date Prev] [Date Next] [Thread Prev] [Thread Next]

Re: Executing variable XPath queries in XSLT


Hi Joe,

> And I would like to then execute this query using $xpath-query in a
> select statement. I would like to do this entirely in XSLT using no
> extension mechanisms. I'm wondering if there are any tricks, known
> ways to execute these kinds of expressions.

You've identified the two best ways: a two-phase transformation and an
extension function.

You *can* do it in one XSLT instead, and it might be worthwhile to
avoid the downsides of the other two methods, as long as the paths
that you're using aren't at all complicated (like they don't involve
predicates).  Basically, you can work through the string, traversing
the document as you go.  Create a template that matches an element and
takes a path as a parameter:

<xsl:template match="/|*" mode="path">
   <xsl:param name="path" />
   ...
</xsl:template>

If the $path parameter contains a '/' then you need to walk down to
the child element that's named before the '/' in the $path, passing
down the $path parameter after the '/':

<xsl:template match="/|*" mode="path">
   <xsl:param name="path" />
   <xsl:choose>
      <xsl:when test="contains($path, '/')">
         <xsl:apply-templates
               select="*[name() = substring-before($path, '/')]">
            <xsl:with-param name="path"
                            select="substring-after($path, '/')" />
         </xsl:apply-templates>
      </xsl:when>
      <xsl:otherwise>
         ...
      </xsl:otherwise>
   </xsl:choose>
</xsl:template>

If there isn't a '/' in the $path, then you're one step away from your
destination.  You want to then somehow activate the rule.  I guess the
easiest way to do this would be to be passing the rule down along with
the path, and then apply templates to the rule with the relevant node
passed as a parameter:

<xsl:template match="/|*" mode="path">
   <xsl:param name="rule" select="/.." />
   <xsl:param name="path" select="substring($rule/expression, 2)" />
   <xsl:choose>
      <xsl:when test="contains($path, '/')">
         <xsl:apply-templates
               select="*[name() = substring-before($path, '/')]">
            <xsl:with-param name="path"
                            select="substring-after($path, '/')" />
            <xsl:with-param name="rule" select="$rule" />
         </xsl:apply-templates>
      </xsl:when>
      <xsl:otherwise>
         <xsl:apply-templates select="$rule">
            <xsl:with-param name="node"
                            select="*[name() = $path]" />
         </xsl:apply-templates>
      </xsl:otherwise>
   </xsl:choose>
</xsl:template>

Note that the above template leaves a lot to be desired - it only
deals with element hierarchies, not attributes, doesn't handle
predicates at all, doesn't deal well with whitespace and so on.
Really I'm giving it as an example of the kind of thing that you have
to do to interpret XPaths dynamically within XSLT without using an
extension function.

Cheers,

Jeni

---
Jeni Tennison
http://www.jenitennison.com/


 XSL-List info and archive:  http://www.mulberrytech.com/xsl/xsl-list


Index Nav: [Date Index] [Subject Index] [Author Index] [Thread Index]
Message Nav: [Date Prev] [Date Next] [Thread Prev] [Thread Next]