[XSL-LIST Mailing List Archive Home] [By Thread] [By Date] [Recent Entries] [Reply To This Message]

Re: xsl with dynamic xpath statement from param and v

Subject: Re: xsl with dynamic xpath statement from param and variable
From: "G. Ken Holman" <gkholman@xxxxxxxxxxxxxxxxxxxx>
Date: Wed, 05 Sep 2007 21:01:33 -0400
Re:  xsl with dynamic xpath statement from param and  v
At 2007-09-06 11:38 +1200, Ralph Price wrote:
My problem seems like it should be simple

Essentially there are nodes in my xml that I wish to discard based on a
child value existing in that node. That value is to be supplied by a
param.

The original data looks like:
...
---------------------------------------------

I only wish to retain in the output from the xsl the item elements
where, in this case the <dict id="RT.VAL.CANCELDATE"> does not have a
<val> child.

So far the stylesheet looks like:

There are a number of aspects of poor form that you should change.


<xsl:stylesheet xmlns:xsl="http://www.w3.org/1999/XSL/Transform"
version="1.0">
        <xsl:output omit-xml-declaration="yes" indent="yes"/>
        <xsl:param name="argDictItem">RT.VAL.CANCELDATE</xsl:param>
        <xsl:variable name="sgl_qte">%27</xsl:variable>

This method of escaping text is not supported in XML. That does not represent a single quote.


<xsl:variable name="xpathDictItem"
select="concat('group/dict[@id=',$sgl_qte,$argDictItem,$sgl_qte,']/val')
"/>

XSLT, as standardized, does not support dynamic evaluation of XPath syntax from a string as you have composed above. Some vendors offer such an extension but extensions are not portable.


        <xsl:template match="/">
        <xsl:comment>
        $xpathDictItem = <xsl:value-of select="$xpathDictItem"/>
        </xsl:comment>
                <xsl:copy>
                        <xsl:apply-templates select="node()"/>
                </xsl:copy>

You don't need to copy the root node, it is implicitly in the result.


        </xsl:template>
        <xsl:template match="node()">

This template rule matches elements, comments, processing instructions and text nodes.


                <xsl:if test="name()!='item'">
                        <!-- carry on copying nodes -->
                        <xsl:copy>
                                <xsl:apply-templates select="node()"/>
                        </xsl:copy>
                </xsl:if>
                <xsl:if test="name()='item'">

The above can be replaced with two template matches.


The use of name()='item' is poor form and when you work with namespaces it will fail.

                        <!-- copy item node only if the argDictItem does
not have a value -->
                        <xsl:choose>
                                <xsl:when test="not($xpathDictItem)">

This does not evaluate the XPath syntax ... this is just checking the string for being empty ... the string is never empty so this is will never be triggered.


                                        <xsl:comment>
                                node discarded - variable value used
                                </xsl:comment>
                                </xsl:when>
                                <xsl:when
test="group/dict[@id='RT.VAL.CANCELDATE']/val">

This is where the change can be made.


                                        <xsl:comment>
                                node discarded - hardcoded value used
                                        </xsl:comment>
                                </xsl:when>
                                <xsl:otherwise>
                                        <xsl:copy>
                                                <xsl:apply-templates
select="node()"/>
                                        </xsl:copy>
                                </xsl:otherwise>
                        </xsl:choose>
                </xsl:if>
        </xsl:template>
</xsl:stylesheet>
...
However I wish to be able to delete the <item> elements based on the
argDictItem parameter rather than my hardcoded value.

In XSLT 1.0 a template rule cannot include a variable reference, while in XSLT 2.0 it can. I've written two solutions since the XSLT 2 is more elegant with the template matches.


And are you sure you wanted to wipe out your source attributes in your target? I assumed this was an oversight, so I'm preserving them. You can easily remove them.

Any leads would be most appreciated.

Two solutions are below. I hope this helps in many ways ... it would seem that you've been misdirected in your XSLT techniques.


. . . . . . . . . Ken


T:\ftemp>type ralph.xml <origenxml xmlns=""> <data> <item> <id>07011*810*00*</id> <obj>RT.VALUATION</obj> <group> <id>MAIN</id> <dict id="RT.VAL.ID.RAW"> <desc>valuation number</desc> <val>07011*810*00*</val> </dict> <dict id="RT.VAL.CANCELDATE"> <desc>cancel date</desc> <val>01 Jan 2006</val> </dict> </group> </item> <item> <id>07011*810*06*</id> <obj>RT.VALUATION</obj> <group> <id>MAIN</id> <dict id="RT.VAL.ID.RAW"> <desc>valuation number</desc> <val>07011*810*06*</val> </dict> <dict id="RT.VAL.CANCELDATE"> <desc>cancel date</desc> </dict> </group> </item> </data> </origenxml>

T:\ftemp>type ralph.xsl
<xsl:stylesheet xmlns:xsl="http://www.w3.org/1999/XSL/Transform"
                version="1.0">
  <xsl:output omit-xml-declaration="yes" indent="yes"/>
  <xsl:param name="argDictItem">RT.VAL.CANCELDATE</xsl:param>

<xsl:template match="/">
  <xsl:comment>
    $argDictItem = <xsl:value-of select="$argDictItem"/>
  </xsl:comment>
  <xsl:apply-templates select="node()"/>
</xsl:template>

<xsl:template match="*">
  <!--preserve this element-->
  <xsl:copy>
    <xsl:copy-of select="@*"/>
    <xsl:apply-templates select="node()"/>
  </xsl:copy>
</xsl:template>

<xsl:template match="item">
  <!-- copy item node only if the argDictItem does not have a value -->
  <xsl:choose>
    <xsl:when test="group/dict[@id=$argDictItem]/val">
      <xsl:comment>
node discarded - detected <xsl:value-of select="$argDictItem"/> with a val
      </xsl:comment>
    </xsl:when>
    <xsl:otherwise>
      <xsl:copy>
        <xsl:copy-of select="@*"/>
        <xsl:apply-templates
          select="node()"/>
      </xsl:copy>
    </xsl:otherwise>
  </xsl:choose>
</xsl:template>

</xsl:stylesheet>

T:\ftemp>call xslt ralph.xml ralph.xsl ralph.out

T:\ftemp>type ralph.out
<!--
    $argDictItem = RT.VAL.CANCELDATE--><origenxml>

   <data>
                <!--
node discarded - detected RT.VAL.CANCELDATE with a val
      -->

<item>

<id>07011*810*06*</id>

<obj>RT.VALUATION</obj>

<group>

<id>MAIN</id>

<dict id="RT.VAL.ID.RAW">

<desc>valuation number</desc>

<val>07011*810*06*</val>

</dict>

<dict id="RT.VAL.CANCELDATE">

<desc>cancel date</desc>

</dict>

</group>

</item>

</data>

</origenxml>
T:\ftemp>type ralph2.xsl
<xsl:stylesheet xmlns:xsl="http://www.w3.org/1999/XSL/Transform"
                version="2.0">
  <xsl:output omit-xml-declaration="yes" indent="yes"/>
  <xsl:param name="argDictItem">RT.VAL.CANCELDATE</xsl:param>

<xsl:template match="/">
  <xsl:comment>
    $argDictItem = <xsl:value-of select="$argDictItem"/>
  </xsl:comment>
  <xsl:apply-templates select="node()"/>
</xsl:template>

<xsl:template match="*">
  <!--preserve this element-->
  <xsl:copy>
    <xsl:copy-of select="@*"/>
    <xsl:apply-templates select="node()"/>
  </xsl:copy>
</xsl:template>

<xsl:template match="item[group/dict[@id=$argDictItem]/val]">
  <xsl:comment>
node discarded - detected <xsl:value-of select="$argDictItem"/> with a val
  </xsl:comment>
</xsl:template>

</xsl:stylesheet>
T:\ftemp>call xslt2 ralph.xml ralph2.xsl ralph2.out
<!--
$argDictItem = RT.VAL.CANCELDATE--><origenxml>
<data>
<!--
node discarded - detected RT.VAL.CANCELDATE with a val
-->
<item>
<id>07011*810*06*</id>
<obj>RT.VALUATION</obj>
<group>
<id>MAIN</id>
<dict id="RT.VAL.ID.RAW">
<desc>valuation number</desc>
<val>07011*810*06*</val>
</dict>
<dict id="RT.VAL.CANCELDATE">
<desc>cancel date</desc>
</dict>
</group>
</item>
</data>
</origenxml>



-- Upcoming public training: XSLT/XSL-FO Sep 10, UBL/code lists Oct 1 World-wide corporate, govt. & user group XML, XSL and UBL training RSS feeds: publicly-available developer resources and training G. Ken Holman mailto:gkholman@xxxxxxxxxxxxxxxxxxxx Crane Softwrights Ltd. http://www.CraneSoftwrights.com/s/ Box 266, Kars, Ontario CANADA K0A-2E0 +1(613)489-0999 (F:-0995) Male Cancer Awareness Jul'07 http://www.CraneSoftwrights.com/s/bc Legal business disclaimers: http://www.CraneSoftwrights.com/legal

Current Thread

PURCHASE STYLUS STUDIO ONLINE TODAY!

Purchasing Stylus Studio from our online shop is Easy, Secure and Value Priced!

Buy Stylus Studio Now

Download The World's Best XML IDE!

Accelerate XML development with our award-winning XML IDE - Download a free trial today!

Don't miss another message! Subscribe to this list today.
Email
First Name
Last Name
Company
Subscribe in XML format
RSS 2.0
Atom 0.3
Site Map | Privacy Policy | Terms of Use | Trademarks
Free Stylus Studio XML Training:
W3C Member
Stylus Studio® and DataDirect XQuery ™are products from DataDirect Technologies, is a registered trademark of Progress Software Corporation, in the U.S. and other countries. © 2004-2013 All Rights Reserved.