I have a XML that looks like this:
<?xml version="1.0"?>
<RootName>
<RandomNode v="someValue"/>
<Series>
<Idendity v="C16"/>
<CodeOut v="C41073"/>
<Period>
<TimePeriod v="2013-07-18T22:00Z/2013-07-19T22:00Z"/>
<Resolution v="PT60M"/>
<Interval>
<Pos v="1"/>
<Qty v="14.1"/>
</Interval>
<Interval>
<Pos v="2"/>
<Qty v="20.7"/>
</Interval>
And I need a xPath that returns all the Period
nodes which matches these conditions:
CodeOut
/ CodeIn
has the value of any of the values that I have in an array CodeOut
can be named CodeOut
or CodeIn
, but only one of these TimePeriod
must match The only node that repeates over the xml is the Series
node. In other words, there is only one Period
per Series
, but there is a lot of different Series
.
For example, get all Period
nodes which have his Codeout
or CodeIn
value to being C41073
or B85028
and the date being 2013-07-18
.
I tried, to match the multiple names, using something like:
//*[@v="C41073"] | //*[@v="B85028"] | ...
But I think it will be better if only matches the correct nodes, just in case some other node has the same value, isn't it?
I was searching to use something like "contains", but it works in a different way.
I'm using .Net, if that matters, and I'm going to use this xPath on the .SelectNodes()
function.
EDIT:
Something strange is happening. Maybe the syntax is not correct. Look at this tests:
This: doc.SelectNodes("/*")(0).Name
is returning RootName
This: doc.SelectNodes("/*/*").Count
is returning 912
This: doc.SelectNodes("/*/*")(11).Name
is returning Series
But this: doc.SelectNodes("/RootName").Count
is returning 0
This: doc.SelectNodes("/*/Series").Count
is returning 0
And this: doc.SelectNodes("/*/RootName").Count
is returning 0
Making all the other xPath sequences suggested in answers not working.
EDIT:
Ok, it was the namespace, I did this:
Dim xmlnsManager As Xml.XmlNamespaceManager = New System.Xml.XmlNamespaceManager(doc.NameTable)
xmlnsManager.AddNamespace("ns", "http://example")
And adding ns:
before every element node name in the xPath sequence. (See this for more information about it: Is it possible to specify the namespace prefix just once in a xpath expression? )
To select all of the Period
elements limited just by the CodeIn
/ CodeOut
list, you could do something like this:
/RootName/Series[(CodeOut/@v = 'C41073') or (CodeOut/@v = 'B85028') or (CodeIn/@v = 'C41073') or (CodeIn/@v = 'B85028')]/Period
If you don't want to list each item in the list as a separate condition, you could concatenate them all together into a delimited list and then use the contains
function, like this:
/RootName/Series[(CodeOut/@v and contains('|C41073|B85028|', concat('|', CodeOut/@v, '|'))) or (CodeIn/@v and contains('|C41073|B85028|', concat('|', CodeIn/@v, '|')))]/Period
Notice, to avoid the problem with a substring like C4
matching the full value, like C41073
, you need to concatenate the delimiter before and after the attribute value. Also, you need to make sure your delimiter exists at the beginning and ending of the delimited list of values. Also, whatever delimiter you choose must be an invalid character which would never occur in any of the values in the list.
However, limiting it also by the TimePeriod
will be a bit more problematic, since it appears to be a non-standard time range value. If the start and end times were stored in separate nodes, it would be easier.
If all you need to do is match an exact TimePeriod
value, for instance, you could just do something like this:
/RootName/Series[(CodeOut/@v = 'C41073') or (CodeOut/@v = 'B85028') or (CodeIn/@v = 'C41073') or (CodeIn/@v = 'B85028')]/Period[TimePeriod/@v = '2013-07-18T22:00Z/2013-07-19T22:00Z']
You can split the string on the /
character, with substring-before(TimePeriod, '/')
and substring-after(TimePeriod, '/')
, but unless you are using XPath 2.0, you can't compare strings to see if they are greater or less than. If you are using 2.0, you could compare each of those substrings with the search value using the compare
function, but it's still messy. It's probably best to handle that time-range comparison in your .NET code.
The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.