This:
<xsl:variable name="matches" select="$set1[starts-with(., $set2)]"/>
will set $matches
to a node-set containing every node in $set1
whose text value starts with the text value of a node in $set2. That's what you're looking for, right?
Edit:
Well, I'm just wrong about this. Here's why.
starts-with
expects its two arguments to both be strings. If they're not, it will convert them to strings before evaluating the function.
If you give it a node-set as one of its arguments, it uses the string value of the node-set, which is the text value of the first node in the set. So in the above, $set2
never gets searched; only the first node in the list ever gets examined, and so the predicate will only find nodes in $set1
that start with the value of the first node in $set2
.
I was misled because this pattern (which I've been using a lot in the last few days) does work:
<xsl:variable name="hits" select="$set1[. = $set2]"/>
But that predicate is using an comparison between node-sets, not between text values.
The ideal way to do this would be by nesting predicates. That is, "I want to find every node in $set1
for which there's a node in $set2
whose value starts with..." and here's where XPath breaks down. Starts with what? What you'd like to write is something like:
<xsl:variable name="matches" select="$set1[$set2[starts-with(?, .)]]"/>
only there's no expression you can write for the ?
that will return the node currently being tested by the outer predicate. (Unless I'm missing something blindingly obvious.)
To get what you want, you have to test each node individually:
<xsl:variable name="matches">
<xsl:for-each select="$set1">
<xsl:if test="$set2[starts-with(current(), .)]">
<xsl:copy-of select="."/>
</xsl:if>
</xsl:for-each>
</xsl:variable>
That's not a very satisfying solution because it evaluates to a result tree fragment, not a node-set. You'll have to use an extension function (like msxsl:node-set
) to convert the RTF to a node-set if you want to use the variable in an XPath expression.
Use:
(/bookstore/book[@location='US'])[1]
This will first get the book elements with the location attribute equal to 'US'. Then it will select the first node from that set. Note the use of parentheses, which are required by some implementations.
Note, this is not the same as /bookstore/book[1][@location='US']
unless the first element also happens to have that location attribute.
Best Answer
This is a FAQ:
means: all
someName
elements in the document, that are the thirdsomeName
child of their parent -- there may be many such elements.What you want is exactly the 3rd
someName
element:Explanation: the
[]
has a higher precedence (priority) than//
. Remember always to put expressions of the type//someName
in brackets when you need to specify the Nth node of their selected node-list.