|
|
 |
| XSLT General questions and answers about XSLT. For issues strictly specific to the book XSLT 1.1 Programmers Reference, please post to that forum instead. |
Welcome to the p2p.wrox.com Forums.
You are currently viewing the XSLT section of the Wrox p2p Programmer to Programmer discussion community. This is a community of more than 40,000 computer programmers including Wrox book authors and readers. As a guest, you can read any forum posting. By joining our free Wrox p2p community you can post your own programming questions and respond to other programmers’ questions. Registered users also don't have to see the ads that are displayed to guests. Registration is fast, simple and absolutely free so please, join today!
Join today and post to win prizes! Post more to increase your chances of being Wrox’s top poster of the month.
|
 |

July 15th, 2003, 08:20 PM
|
|
Registered User
|
|
Join Date: Jun 2003
Location: Menlo Park, CA, USA.
Posts: 5
Thanks: 0
Thanked 0 Times in 0 Posts
|
|
XPath: set operation with a disjoint node set
input file:
<foo type="a"/>
<foo type="b"/>
<foo type="c"/>
<bar type="a"/>
<bar type="b"/>
Now, say I've got node sets:
<xsl:variable name="A" select="foo"/>
<xsl:variable name="B" select="bar"/>
And I'd like to select any <foo>s with types not found in the set of <bar>s. In this example, that would be just the 3rd <foo>. How would I do this?
My first thought was to select:
$A[string(@type) != string($B/@type)]
...but that will only select nodes from A whose type is not "a" (the first <foo>'s type).
Any clues?
Thanks,
Rich
|

July 16th, 2003, 03:31 AM
|
 |
Wrox Author
|
|
Join Date: Jun 2003
Location: Exeter, , United Kingdom.
Posts: 2,922
Thanks: 0
Thanked 13 Times in 12 Posts
|
|
You don't want or need string function and you need to change from != to not:
$A[not(@type = $B/@type)]
not means there are no matches, i.e. no @type in $B matches the @type of $A, != means they all don't match, if any non-match can be found then include the node.
If you're xml is:
Code:
<root>
<foo type="a"/>
<foo type="b"/>
<foo type="c"/>
<bar type="a"/>
<bar type="b"/>
</root>
and xsl is:
Code:
<xsl:stylesheet version="1.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform">
<xsl:template match="/">
<xsl:variable name="A" select="root/foo"/>
<xsl:variable name="B" select="root/bar"/>
<xsl:for-each select="$A[@type != $B/@type]">
<xsl:text>#x0a;</xsl:text><xsl:copy-of select="."/>
</xsl:for-each>
</xsl:template>
</xsl:stylesheet>
Run this and then change select to:
$A[@type != $B/@type]
to see difference.
--
Joe
|

July 16th, 2003, 05:47 AM
|
 |
Wrox Author
|
|
Join Date: Jun 2003
Location: Exeter, , United Kingdom.
Posts: 2,922
Thanks: 0
Thanked 13 Times in 12 Posts
|
|
Sorry, the initial xsl should have been:
Code:
<xsl:stylesheet version="1.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform">
<xsl:template match="/">
<xsl:variable name="A" select="root/foo"/>
<xsl:variable name="B" select="root/bar"/>
<xsl:for-each select="$A[not(@type = $B/@type)]">
<xsl:text>#x0a;</xsl:text><xsl:copy-of select="."/>
</xsl:for-each>
</xsl:template>
</xsl:stylesheet>
I pasted the wrong version...
--
Joe
|

July 16th, 2003, 06:20 AM
|
|
Friend of Wrox
|
|
Join Date: Jun 2003
Location: Nor Hachin, Kotayk, Armenia.
Posts: 147
Thanks: 0
Thanked 0 Times in 0 Posts
|
|
The whole problem is in the "magical" properties of the "!=" operator and in the use of the "string" function here.
Look why your code is not working:
The function "string" returns the string value of the first node when the argument is a nodeset. So in your XPath expression you compare the context node's attribute's string-value to the first "foo" element's attribute value.
Even
Code:
$A[@type != $B/@type]
is not working again due to the rules for "!=" operator. Actually, "=" operator "returns" true for nodesets NS1 and NS2 as arguments when there is a node n1 in NS1 and node n2 in NS2 such that their string-values are the same. And "!=" is not a logical negation of "=": for 2 nodesets "!=" "returns" true if there is at least one pair of (n1, n2) [n1 is in NS1 and n2 is in NS2] such that their string-values are not the same. Therefore there are situations when "not(NS1 = NS2)" is not equivalent to "NS1 != NS2".
That's why you have to use "not" instead of "!=" here and you have to compare nodesets instead of using"string" function.
The working XPath expression is
Code:
$A[not(@type = $B/@type)]
Regards,
Armen
|

July 16th, 2003, 02:30 PM
|
|
Registered User
|
|
Join Date: Jun 2003
Location: Menlo Park, CA, USA.
Posts: 5
Thanks: 0
Thanked 0 Times in 0 Posts
|
|
Wow, thanks for setting me straight, guys!
|

May 5th, 2008, 11:33 AM
|
|
Registered User
|
|
Join Date: May 2008
Location: , , .
Posts: 4
Thanks: 0
Thanked 0 Times in 0 Posts
|
|
I have a similar issue but I'm having a hard time trying to figure out how to make it work. I'm trying to get the union of two node sets with one having priority.
Example:
<defaults>
<color>red</color>
<size>10</size>
<flavor>cherry</flavor>
</defaults>
<config>
<color>black</color>
<flavor>blueberry</flavor>
</config>
So, it seems like I should be able to do something like this:
<xsl:variable name="class" select="defaults"></xsl:param>
<xsl:variable name="instance" select="config"></xsl:param>
<xsl:for-each select="$class[not(name() != $instance/name())]">
<xsl:text>#x0a;</xsl:text><xsl:copy-of select="."/>
</xsl:for-each>
<xsl:for-each select="$instance">
<xsl:copy-of select="."/>
</xsl:for-each>
The results should end up something like this then:
<size>10</size>
<color>black</color>
<flavor>blueberry</flavor>
I know I've probably presented this too simply so please let me know what other info I could provide to help it make sense. The main issue seems to be the predicate not being allowed to match on name().
|

May 5th, 2008, 11:58 AM
|
 |
Wrox Author
Points: 12,735, Level: 48 |
|
|
Join Date: Apr 2004
Location: Reading, Berks, United Kingdom.
Posts: 3,923
Thanks: 0
Thanked 82 Times in 80 Posts
|
|
You first need to say whether you are using XSLT 1.0 or XSLT 2.0.
In 2.0 this is best treated as a grouping problem:
<xsl:for-each-group select="defaults/*, config/*" group-by="node-name()">
<xsl:copy-of select="current-group()[last()]"/>
</xsl:for-each>
Michael Kay
http://www.saxonica.com/
Author, XSLT Programmer's Reference and XPath 2.0 Programmer's Reference
|

May 6th, 2008, 10:24 AM
|
|
Registered User
|
|
Join Date: May 2008
Location: , , .
Posts: 4
Thanks: 0
Thanked 0 Times in 0 Posts
|
|
I'm using XSLT 1.0
|
| Thread Tools |
Search this Thread |
|
|
|
| Display Modes |
Linear Mode
|
Posting Rules
|
You may not post new threads
You may not post replies
You may not post attachments
You may not edit your posts
HTML code is Off
|
|
|
|
 |