0
votes

I am trying to do a XSL transformation on an XML document of all the bus routes and bus stops within my city. In doing so I'm using a for-each select that selects all the "stop" nodes that contain the route number I'm passing in as a parameter.

When I go to run my program, none of the values seem to be getting selected and I am wondering if my syntax is invalid or can you not use parameters in an xsl:for-each select statement?

Here is my xsl:

<xsl:stylesheet version="1.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform">

  <xsl:param name="route_num"></xsl:param>
  <xsl:param name="num_stops" />

  <xsl:template match="/">
    <!-- ... -->
    <xsl:for-each select="allstops/stop[contains(routes,$route_num)]">
      <xsl:sort select="@number"/>
        <tr>
        <td><xsl:value-of select="@number"/></td>
        <td><xsl:value-of select="@name"/></td>
        <td><xsl:value-of select="location/latitude"/></td>
        <td><xsl:value-of select="location/longitude"/></td>
        <td><xsl:value-of select="routes"/></td>
       </tr>
    </xsl:for-each>
    <!-- ... -->
  </xsl:template>
</xsl:stylesheet>

And here is a sample of the XML:

<stop number="20" name="Adelaide &amp; Ada NB">
    <location>
      <latitude>42.9742886</latitude>
      <longitude>-81.2252341</longitude>
    </location>
    <routes>16</routes>
</stop>

So lets say an XML node contains a route of 16, it should go through all the nodes and pull the data into the fields I have set up, unless my syntax is wrong with the XSL should it not?

EDIT: the routes tag can contain multiple route numbers, which is why I have been using contains:

<stop number="408" name="Clarence &amp; King St NB">
    <location>
      <latitude>42.9835093</latitude>
      <longitude>-81.2471596</longitude>
    </location>
    <routes>05, 09, 12, 19, 23</routes>
</stop>

EDIT #2: XML has no namespaces.

2
If there is any chance at all to change the "routes can be a comma-delimited list" part then by all means change it. If you're stuck with it, at least use something that avoids false positives (i.e. 6 also matching 16): contains(concat(',', translate(routes, ' ', ''), ','), contcat(',', $route_num, ',')). Yes, that's ugly, but that's direct a consequence of using XML wrong. - Tomalak
Other than the problem of potential false positives explained above by Tomalak, there is no reason why your select statement should not work. That is, no reason that can be seen from the partial code you have posted. Did you check that the parameter is successfully passed to the stylesheet? - michael.hor257k
Well that is basically all there is too it. An XSLT transform being done in C# written to a WebBrowser control. It seems that it is not even entering the for-each with my select statement. Could it be the template match? - Delete
It must be something to do with me writing to my WebBrowser control, because its completely skipping the xsl:for-each in my XSLT. - Delete

2 Answers

0
votes

The contains() function works with strings, not with nodes. What you need here is a simple node-set comparison:

<xsl:for-each select="allstops/stop[routes=$route_num]">
0
votes

contains() is a string function (i.e. 'foo' contains 'o'). You're using it wrong, you probably want allstops/stop[routes = $route_num].

Other than that - yes, it's possible to use parameter values or variables in XPath expressions, the <xsl:for-each> will use whatever the XPath returns.

From your example alone it's not possible to tell where the error in your XPath is. Build the expression again, trying to find out where it fails.