What am I doing wrong in this XPath expression?

S

steve bull

I have the following code snippet to read the colorRange attributes for the colorRangeSwatch in the xml file listed
below.

string expr = "/swatches[colorRangeSwatch='All Red Colors']/colorRangeSwatch/colorRange";
XmlElement crsElement = (XmlElement)m_colorRangeSwatchDoc.SelectSingleNode(expr);
bool fr = bool.Parse(crsElement.GetAttribute("fixed").ToString());


The element returned is always the 1st, All Blue Colors, why doesn't the expression filter on the colorRangeSwatch
value?

Any ideas would be welcome.

Thanks,

Steve



The xml file which I am trying to read from :

<?xml version="1.0" encoding="utf-8" standalone="no" ?>
<swatches id="CustomColorRangeSwatches">
<colorRangeSwatch>All Blue Colors
<colorRange fixed="True"
red="0" green="0" blue="193"
redMin="0" redMax="0"
greenMin="0" greenMax="0"
blueMin="0" blueMax="255" />
</colorRangeSwatch>
<colorRangeSwatch>All Red Colors
<colorRange fixed="True"
red="183" green="0" blue="0"
redMin="0" redMax="255"
greenMin="0" greenMax="0"
blueMin="0" blueMax="0" />
</colorRangeSwatch>
</swatches>
 
D

Dimitre Novatchev

steve bull said:
I have the following code snippet to read the colorRange attributes for
the colorRangeSwatch in the xml file listed
below.

string expr = "/swatches[colorRangeSwatch='All Red
Colors']/colorRangeSwatch/colorRange";
XmlElement crsElement =
(XmlElement)m_colorRangeSwatchDoc.SelectSingleNode(expr);
bool fr =
bool.Parse(crsElement.GetAttribute("fixed").ToString());


The element returned is always the 1st, All Blue Colors, why doesn't the
expression filter on the colorRangeSwatch
value?

Any ideas would be welcome.

Thanks,

Steve



The xml file which I am trying to read from :

<?xml version="1.0" encoding="utf-8" standalone="no" ?>
<swatches id="CustomColorRangeSwatches">
<colorRangeSwatch>All Blue Colors
<colorRange fixed="True"
red="0" green="0" blue="193"
redMin="0" redMax="0"
greenMin="0" greenMax="0"
blueMin="0" blueMax="255" />
</colorRangeSwatch>
<colorRangeSwatch>All Red Colors
<colorRange fixed="True"
red="183" green="0" blue="0"
redMin="0" redMax="255"
greenMin="0" greenMax="0"
blueMin="0" blueMax="0" />
</colorRangeSwatch>
</swatches>

There are at least three problems:

1. Your source xml is unreadable -- in case you really hope someone might
give it a try, provide a more readable version, maybe something like this:

<swatches id="CustomColorRangeSwatches">
<colorRangeSwatch>All Blue Colors
<colorRange fixed="True"
red="0" green="0" blue="193"
redMin="0" redMax="0"
greenMin="0" greenMax="0"
blueMin="0" blueMax="255" />
</colorRangeSwatch>
<colorRangeSwatch>All Red Colors
<colorRange fixed="True"
red="183" green="0" blue="0"
redMin="0" redMax="255"
greenMin="0" greenMax="0"
blueMin="0" blueMax="0" />
</colorRangeSwatch>
</swatches>

2. The comparison:
colorRangeSwatch='All Red Colors'
will most probably return false for the top node. There are some NL
characters after the starting text.

3. Most important:

/swatches[colorRangeSwatch='All Red
Colors']/colorRangeSwatch/colorRange
-------------------------------------------------------------^^^^^^^^^^^^^^^^^^^

Even if the comparison in the predicate returns true, the location
step following it selects *all* "colorRangeSwatch" elements children of the
top element "swatches"

Thus, if the comparison is trye, the expression above will select all
"colorRange" children of all "colorRangeSwatch" children of the top element
"swatches".

Then the SelectSingleNode() method returns the first in document order
such "colorRange" element -- and you say you want the second.


One XPath expression that will select the node you seem to want is:

/swatches/colorRangeSwatch[starts-with(.,'All Red Colors')]/colorRange



Hope this helped.


Cheers,
Dimitre Novatchev
 
S

steve bull

Thanks, it works. I don't really understand why but it does appear to do what I want. It has been quite frustrating
trying to figure out the right syntax.

Apart from the xml header line I don't see a difference between the xml you returned and what I posted.


Many thanks,

Steve



steve bull said:
I have the following code snippet to read the colorRange attributes for
the colorRangeSwatch in the xml file listed
below.

string expr = "/swatches[colorRangeSwatch='All Red
Colors']/colorRangeSwatch/colorRange";
XmlElement crsElement =
(XmlElement)m_colorRangeSwatchDoc.SelectSingleNode(expr);
bool fr =
bool.Parse(crsElement.GetAttribute("fixed").ToString());


The element returned is always the 1st, All Blue Colors, why doesn't the
expression filter on the colorRangeSwatch
value?

Any ideas would be welcome.

Thanks,

Steve



The xml file which I am trying to read from :

<?xml version="1.0" encoding="utf-8" standalone="no" ?>
<swatches id="CustomColorRangeSwatches">
<colorRangeSwatch>All Blue Colors
<colorRange fixed="True"
red="0" green="0" blue="193"
redMin="0" redMax="0"
greenMin="0" greenMax="0"
blueMin="0" blueMax="255" />
</colorRangeSwatch>
<colorRangeSwatch>All Red Colors
<colorRange fixed="True"
red="183" green="0" blue="0"
redMin="0" redMax="255"
greenMin="0" greenMax="0"
blueMin="0" blueMax="0" />
</colorRangeSwatch>
</swatches>

There are at least three problems:

1. Your source xml is unreadable -- in case you really hope someone might
give it a try, provide a more readable version, maybe something like this:

<swatches id="CustomColorRangeSwatches">
<colorRangeSwatch>All Blue Colors
<colorRange fixed="True"
red="0" green="0" blue="193"
redMin="0" redMax="0"
greenMin="0" greenMax="0"
blueMin="0" blueMax="255" />
</colorRangeSwatch>
<colorRangeSwatch>All Red Colors
<colorRange fixed="True"
red="183" green="0" blue="0"
redMin="0" redMax="255"
greenMin="0" greenMax="0"
blueMin="0" blueMax="0" />
</colorRangeSwatch>
</swatches>

2. The comparison:
colorRangeSwatch='All Red Colors'
will most probably return false for the top node. There are some NL
characters after the starting text.

3. Most important:

/swatches[colorRangeSwatch='All Red
Colors']/colorRangeSwatch/colorRange
-------------------------------------------------------------^^^^^^^^^^^^^^^^^^^

Even if the comparison in the predicate returns true, the location
step following it selects *all* "colorRangeSwatch" elements children of the
top element "swatches"

Thus, if the comparison is trye, the expression above will select all
"colorRange" children of all "colorRangeSwatch" children of the top element
"swatches".

Then the SelectSingleNode() method returns the first in document order
such "colorRange" element -- and you say you want the second.


One XPath expression that will select the node you seem to want is:

/swatches/colorRangeSwatch[starts-with(.,'All Red Colors')]/colorRange



Hope this helped.


Cheers,
Dimitre Novatchev
 
D

Dimitre Novatchev

steve bull said:
Thanks, it works. I don't really understand why but it does appear to do
what I want. It has been quite frustrating
trying to figure out the right syntax.

Apart from the xml header line I don't see a difference between the xml
you returned and what I posted.

Then it would be worthy to start learning XPath seriously.

Also, using a tool like the XPath Visualizer may prove helpful.


Cheers,
Dimitre Novatchev.

Many thanks,

Steve



steve bull said:
I have the following code snippet to read the colorRange attributes for
the colorRangeSwatch in the xml file listed
below.

string expr = "/swatches[colorRangeSwatch='All Red
Colors']/colorRangeSwatch/colorRange";
XmlElement crsElement =
(XmlElement)m_colorRangeSwatchDoc.SelectSingleNode(expr);
bool fr =
bool.Parse(crsElement.GetAttribute("fixed").ToString());


The element returned is always the 1st, All Blue Colors, why doesn't the
expression filter on the colorRangeSwatch
value?

Any ideas would be welcome.

Thanks,

Steve



The xml file which I am trying to read from :

<?xml version="1.0" encoding="utf-8" standalone="no" ?>
<swatches id="CustomColorRangeSwatches">
<colorRangeSwatch>All Blue Colors
<colorRange fixed="True"
red="0" green="0" blue="193"
redMin="0" redMax="0"
greenMin="0" greenMax="0"
blueMin="0" blueMax="255" />
</colorRangeSwatch>
<colorRangeSwatch>All Red Colors
<colorRange fixed="True"
red="183" green="0" blue="0"
redMin="0" redMax="255"
greenMin="0" greenMax="0"
blueMin="0" blueMax="0" />
</colorRangeSwatch>
</swatches>

There are at least three problems:

1. Your source xml is unreadable -- in case you really hope someone
might
give it a try, provide a more readable version, maybe something like this:

<swatches id="CustomColorRangeSwatches">
<colorRangeSwatch>All Blue Colors
<colorRange fixed="True"
red="0" green="0" blue="193"
redMin="0" redMax="0"
greenMin="0" greenMax="0"
blueMin="0" blueMax="255" />
</colorRangeSwatch>
<colorRangeSwatch>All Red Colors
<colorRange fixed="True"
red="183" green="0" blue="0"
redMin="0" redMax="255"
greenMin="0" greenMax="0"
blueMin="0" blueMax="0" />
</colorRangeSwatch>
</swatches>

2. The comparison:
colorRangeSwatch='All Red Colors'
will most probably return false for the top node. There are some NL
characters after the starting text.

3. Most important:

/swatches[colorRangeSwatch='All Red
Colors']/colorRangeSwatch/colorRange
-------------------------------------------------------------^^^^^^^^^^^^^^^^^^^

Even if the comparison in the predicate returns true, the location
step following it selects *all* "colorRangeSwatch" elements children of
the
top element "swatches"

Thus, if the comparison is trye, the expression above will select all
"colorRange" children of all "colorRangeSwatch" children of the top
element
"swatches".

Then the SelectSingleNode() method returns the first in document order
such "colorRange" element -- and you say you want the second.


One XPath expression that will select the node you seem to want is:

/swatches/colorRangeSwatch[starts-with(.,'All Red Colors')]/colorRange



Hope this helped.


Cheers,
Dimitre Novatchev
 
D

Dimitre Novatchev

steve bull said:
Thanks, it works. I don't really understand why but it does appear to do
what I want.

Your original XPath expression:
/swatches[colorRangeSwatch='All Red
Colors']/colorRangeSwatch/colorRange

has this translation into English:

Select all "colorRange" elements that are children of a "colorRangeSwatch"
element, which is a child of a top element named "swatches", if this top
element has children named "colorRangeSwatch", whose string value is 'All
Red Colors'

It selects the same nodes as this simpler expression because the condition
inside the predicate is true -- the top element satisfies the condition,
therefore all of its colorRangeSwatch/colorRange grand-children will be
selected:

/swatches/colorRangeSwatch/colorRange

But you wanted the colorRange nodes that are children only of the
colorRangeSwatch elements, whose string value starts with
'All Red Colors'

One XPath expression that returns the nodes you wanted is

/swatches/colorRangeSwatch[starts-with(.,'All Red Colors')]/colorRange

The translation of this into English is:

Select all "colorRange" elements, which are children of a "colorRangeSwatch"
element, whose string value starts with the string
'All Red Colors' and which is child of the top element named "swatches".
It has been quite frustrating
trying to figure out the right syntax.

Apart from the xml header line I don't see a difference between the xml
you returned and what I posted.

The difference is only in readability :eek:)

Many thanks,

Steve



steve bull said:
I have the following code snippet to read the colorRange attributes for
the colorRangeSwatch in the xml file listed
below.

string expr = "/swatches[colorRangeSwatch='All Red
Colors']/colorRangeSwatch/colorRange";
XmlElement crsElement =
(XmlElement)m_colorRangeSwatchDoc.SelectSingleNode(expr);
bool fr =
bool.Parse(crsElement.GetAttribute("fixed").ToString());


The element returned is always the 1st, All Blue Colors, why doesn't the
expression filter on the colorRangeSwatch
value?

Any ideas would be welcome.

Thanks,

Steve



The xml file which I am trying to read from :

<?xml version="1.0" encoding="utf-8" standalone="no" ?>
<swatches id="CustomColorRangeSwatches">
<colorRangeSwatch>All Blue Colors
<colorRange fixed="True"
red="0" green="0" blue="193"
redMin="0" redMax="0"
greenMin="0" greenMax="0"
blueMin="0" blueMax="255" />
</colorRangeSwatch>
<colorRangeSwatch>All Red Colors
<colorRange fixed="True"
red="183" green="0" blue="0"
redMin="0" redMax="255"
greenMin="0" greenMax="0"
blueMin="0" blueMax="0" />
</colorRangeSwatch>
</swatches>

There are at least three problems:

1. Your source xml is unreadable -- in case you really hope someone
might
give it a try, provide a more readable version, maybe something like this:

<swatches id="CustomColorRangeSwatches">
<colorRangeSwatch>All Blue Colors
<colorRange fixed="True"
red="0" green="0" blue="193"
redMin="0" redMax="0"
greenMin="0" greenMax="0"
blueMin="0" blueMax="255" />
</colorRangeSwatch>
<colorRangeSwatch>All Red Colors
<colorRange fixed="True"
red="183" green="0" blue="0"
redMin="0" redMax="255"
greenMin="0" greenMax="0"
blueMin="0" blueMax="0" />
</colorRangeSwatch>
</swatches>

2. The comparison:
colorRangeSwatch='All Red Colors'
will most probably return false for the top node. There are some NL
characters after the starting text.

3. Most important:

/swatches[colorRangeSwatch='All Red
Colors']/colorRangeSwatch/colorRange
-------------------------------------------------------------^^^^^^^^^^^^^^^^^^^

Even if the comparison in the predicate returns true, the location
step following it selects *all* "colorRangeSwatch" elements children of
the
top element "swatches"

Thus, if the comparison is trye, the expression above will select all
"colorRange" children of all "colorRangeSwatch" children of the top
element
"swatches".

Then the SelectSingleNode() method returns the first in document order
such "colorRange" element -- and you say you want the second.


One XPath expression that will select the node you seem to want is:

/swatches/colorRangeSwatch[starts-with(.,'All Red Colors')]/colorRange



Hope this helped.


Cheers,
Dimitre Novatchev
 
S

steve bull

Many thanks. I understand what is happening now. I tried quite a few sources for XPath but none of them were really
clear on what was happening in the selection process even though they had quite a few examples. I guess it is always
more difficult when you have to work out an example for the first time.

I hadn't really noticed the functions either. I am surprised though that there does not appear to be a function for
testing equality between two strings.

Thanks again,

Steve







steve bull said:
Thanks, it works. I don't really understand why but it does appear to do
what I want.

Your original XPath expression:
/swatches[colorRangeSwatch='All Red
Colors']/colorRangeSwatch/colorRange

has this translation into English:

Select all "colorRange" elements that are children of a "colorRangeSwatch"
element, which is a child of a top element named "swatches", if this top
element has children named "colorRangeSwatch", whose string value is 'All
Red Colors'

It selects the same nodes as this simpler expression because the condition
inside the predicate is true -- the top element satisfies the condition,
therefore all of its colorRangeSwatch/colorRange grand-children will be
selected:

/swatches/colorRangeSwatch/colorRange

But you wanted the colorRange nodes that are children only of the
colorRangeSwatch elements, whose string value starts with
'All Red Colors'

One XPath expression that returns the nodes you wanted is

/swatches/colorRangeSwatch[starts-with(.,'All Red Colors')]/colorRange

The translation of this into English is:

Select all "colorRange" elements, which are children of a "colorRangeSwatch"
element, whose string value starts with the string
'All Red Colors' and which is child of the top element named "swatches".
It has been quite frustrating
trying to figure out the right syntax.

Apart from the xml header line I don't see a difference between the xml
you returned and what I posted.

The difference is only in readability :eek:)

Many thanks,

Steve



I have the following code snippet to read the colorRange attributes for
the colorRangeSwatch in the xml file listed
below.

string expr = "/swatches[colorRangeSwatch='All Red
Colors']/colorRangeSwatch/colorRange";
XmlElement crsElement =
(XmlElement)m_colorRangeSwatchDoc.SelectSingleNode(expr);
bool fr =
bool.Parse(crsElement.GetAttribute("fixed").ToString());


The element returned is always the 1st, All Blue Colors, why doesn't the
expression filter on the colorRangeSwatch
value?

Any ideas would be welcome.

Thanks,

Steve



The xml file which I am trying to read from :

<?xml version="1.0" encoding="utf-8" standalone="no" ?>
<swatches id="CustomColorRangeSwatches">
<colorRangeSwatch>All Blue Colors
<colorRange fixed="True"
red="0" green="0" blue="193"
redMin="0" redMax="0"
greenMin="0" greenMax="0"
blueMin="0" blueMax="255" />
</colorRangeSwatch>
<colorRangeSwatch>All Red Colors
<colorRange fixed="True"
red="183" green="0" blue="0"
redMin="0" redMax="255"
greenMin="0" greenMax="0"
blueMin="0" blueMax="0" />
</colorRangeSwatch>
</swatches>


There are at least three problems:

1. Your source xml is unreadable -- in case you really hope someone
might
give it a try, provide a more readable version, maybe something like this:

<swatches id="CustomColorRangeSwatches">
<colorRangeSwatch>All Blue Colors
<colorRange fixed="True"
red="0" green="0" blue="193"
redMin="0" redMax="0"
greenMin="0" greenMax="0"
blueMin="0" blueMax="255" />
</colorRangeSwatch>
<colorRangeSwatch>All Red Colors
<colorRange fixed="True"
red="183" green="0" blue="0"
redMin="0" redMax="255"
greenMin="0" greenMax="0"
blueMin="0" blueMax="0" />
</colorRangeSwatch>
</swatches>

2. The comparison:
colorRangeSwatch='All Red Colors'
will most probably return false for the top node. There are some NL
characters after the starting text.

3. Most important:

/swatches[colorRangeSwatch='All Red
Colors']/colorRangeSwatch/colorRange
-------------------------------------------------------------^^^^^^^^^^^^^^^^^^^

Even if the comparison in the predicate returns true, the location
step following it selects *all* "colorRangeSwatch" elements children of
the
top element "swatches"

Thus, if the comparison is trye, the expression above will select all
"colorRange" children of all "colorRangeSwatch" children of the top
element
"swatches".

Then the SelectSingleNode() method returns the first in document order
such "colorRange" element -- and you say you want the second.


One XPath expression that will select the node you seem to want is:

/swatches/colorRangeSwatch[starts-with(.,'All Red Colors')]/colorRange



Hope this helped.


Cheers,
Dimitre Novatchev
 
D

Dimitre Novatchev

I hadn't really noticed the functions either. I am surprised though that
there does not appear to be a function for
testing equality between two strings.

There isn't a "function" for comparing two strings, because this function is
the "=" operator.

the expression

str1 = str2,

where str1 and str2 are strings

is true iff the two strings are equal.

I used the starts-with() function, because in your xml file their were some
newline (NL) characters part of the text nodes.

Another way to eliminate unnecessary white space is to use the
normalize-space() function.


Cheers,
Dimitre Novatchev




steve bull said:
Many thanks. I understand what is happening now. I tried quite a few
sources for XPath but none of them were really
clear on what was happening in the selection process even though they had
quite a few examples. I guess it is always
more difficult when you have to work out an example for the first time.

I hadn't really noticed the functions either. I am surprised though that
there does not appear to be a function for
testing equality between two strings.

Thanks again,

Steve







steve bull said:
Thanks, it works. I don't really understand why but it does appear to do
what I want.

Your original XPath expression:
/swatches[colorRangeSwatch='All Red
Colors']/colorRangeSwatch/colorRange

has this translation into English:

Select all "colorRange" elements that are children of a "colorRangeSwatch"
element, which is a child of a top element named "swatches", if this top
element has children named "colorRangeSwatch", whose string value is 'All
Red Colors'

It selects the same nodes as this simpler expression because the condition
inside the predicate is true -- the top element satisfies the condition,
therefore all of its colorRangeSwatch/colorRange grand-children will be
selected:

/swatches/colorRangeSwatch/colorRange

But you wanted the colorRange nodes that are children only of the
colorRangeSwatch elements, whose string value starts with
'All Red Colors'

One XPath expression that returns the nodes you wanted is

/swatches/colorRangeSwatch[starts-with(.,'All Red
Colors')]/colorRange

The translation of this into English is:

Select all "colorRange" elements, which are children of a
"colorRangeSwatch"
element, whose string value starts with the string
'All Red Colors' and which is child of the top element named "swatches".
It has been quite frustrating
trying to figure out the right syntax.

Apart from the xml header line I don't see a difference between the xml
you returned and what I posted.

The difference is only in readability :eek:)

Many thanks,

Steve



On Sat, 18 Jun 2005 06:40:53 +1000, "Dimitre Novatchev"




I have the following code snippet to read the colorRange attributes
for
the colorRangeSwatch in the xml file listed
below.

string expr = "/swatches[colorRangeSwatch='All Red
Colors']/colorRangeSwatch/colorRange";
XmlElement crsElement =
(XmlElement)m_colorRangeSwatchDoc.SelectSingleNode(expr);
bool fr =
bool.Parse(crsElement.GetAttribute("fixed").ToString());


The element returned is always the 1st, All Blue Colors, why doesn't
the
expression filter on the colorRangeSwatch
value?

Any ideas would be welcome.

Thanks,

Steve



The xml file which I am trying to read from :

<?xml version="1.0" encoding="utf-8" standalone="no" ?>
<swatches id="CustomColorRangeSwatches">
<colorRangeSwatch>All Blue Colors
<colorRange fixed="True"
red="0" green="0" blue="193"
redMin="0" redMax="0"
greenMin="0" greenMax="0"
blueMin="0" blueMax="255" />
</colorRangeSwatch>
<colorRangeSwatch>All Red Colors
<colorRange fixed="True"
red="183" green="0" blue="0"
redMin="0" redMax="255"
greenMin="0" greenMax="0"
blueMin="0" blueMax="0" />
</colorRangeSwatch>
</swatches>


There are at least three problems:

1. Your source xml is unreadable -- in case you really hope someone
might
give it a try, provide a more readable version, maybe something like
this:

<swatches id="CustomColorRangeSwatches">
<colorRangeSwatch>All Blue Colors
<colorRange fixed="True"
red="0" green="0" blue="193"
redMin="0" redMax="0"
greenMin="0" greenMax="0"
blueMin="0" blueMax="255" />
</colorRangeSwatch>
<colorRangeSwatch>All Red Colors
<colorRange fixed="True"
red="183" green="0" blue="0"
redMin="0" redMax="255"
greenMin="0" greenMax="0"
blueMin="0" blueMax="0" />
</colorRangeSwatch>
</swatches>

2. The comparison:
colorRangeSwatch='All Red Colors'
will most probably return false for the top node. There are some
NL
characters after the starting text.

3. Most important:

/swatches[colorRangeSwatch='All Red
Colors']/colorRangeSwatch/colorRange
-------------------------------------------------------------^^^^^^^^^^^^^^^^^^^

Even if the comparison in the predicate returns true, the location
step following it selects *all* "colorRangeSwatch" elements children of
the
top element "swatches"

Thus, if the comparison is trye, the expression above will select
all
"colorRange" children of all "colorRangeSwatch" children of the top
element
"swatches".

Then the SelectSingleNode() method returns the first in document
order
such "colorRange" element -- and you say you want the second.


One XPath expression that will select the node you seem to want is:

/swatches/colorRangeSwatch[starts-with(.,'All Red
Colors')]/colorRange



Hope this helped.


Cheers,
Dimitre Novatchev
 
D

David Carlisle

I hadn't really n oticed the functions either. I am surprised though
that there does not appear to be a function for testing equality between two strings.

You can just use = for that.

David
 

Ask a Question

Want to reply to this thread or ask your own question?

You'll need to choose a username for the site, which only take a couple of moments. After that, you can post your question and our members will help you out.

Ask a Question

Members online

No members online now.

Forum statistics

Threads
473,999
Messages
2,570,247
Members
46,844
Latest member
JudyGvh32

Latest Threads

Top