Reputation: 9613
I have an XML document which looks something like this:
<meadinkent>
<record>
<comp_div>MENSWEAR</comp_div>
<sty_ret_type>ACCESSORIES</sty_ret_type>
<sty_pdt_type>BELTS</sty_pdt_type>
<pdt_category>AWESOME_BELTS</pdt_category>
</record>
<medinkent>
I want to useXPath to select nodes which match all four elements and I'm having trouble getting the boolean syntax right. I'm trying this to match the first two just as a test:
"/meadinkent/record/comp_div[.='" & comp_div & "'] and /meadinkent/record/sty_ret_type[.='" & sty_ret_type & "']"
Which is failing, saying no nodes are returned. Obviously I'm being very stupid - what am I doing wrong?
Cheers, mAtt
Upvotes: 29
Views: 74161
Reputation: 11904
or you could use linq to XML and do it like this :
var match = XElement.Parse(xmlString);
var matches = from xml in xmlDocument.Elements()
where xml.Element("comp_div").Value == "MENSWEAR"
&& xml.Element("sty_ret_type").Value == "ACCESSORIES"
&& xml.Element("sty_pdt_type").Value == "BELTS"
&& xml.Element("pdt_category").Value == "AWESOME_BELTS"
select xml;
Upvotes: 1
Reputation: 23800
Union
In order to get both nodes you need to use union operator - |
For example, the next query will return both type of nodes - comp_div
and sty_ret_type
:
/meadinkent/record/comp_div | /meadinkent/record/sty_ret_type
Filter by sub-nodes values
In order to filter node based on its sub-nodes values you need to place all conditions in same brackets [nodeA='value1' and nodeB='value2']
For example, the next query will return record nodes whose sub nodes match the filter:
/meadinkent/record[comp_div='MENSWEAR' and sty_ret_type='ACCESSORIES']
A C# union example:
[Test]
public void UnionExample()
{
string xml =
@"<meadinkent>
<record>
<comp_div>MENSWEAR</comp_div>
<sty_ret_type>ACCESSORIES</sty_ret_type>
<sty_pdt_type>BELTS</sty_pdt_type>
<pdt_category>AWESOME_BELTS</pdt_category>
</record>
</meadinkent>";
XDocument xDocument = XDocument.Parse(xml);
IEnumerable<XElement> selectedElements =
xDocument.XPathSelectElements(
"/meadinkent/record/comp_div | /meadinkent/record/sty_ret_type");
Assert.That(selectedElements.Count(), Is.EqualTo(2));
}
A C# filter by sub-nodes example:
[Test]
public void FilterExample()
{
string xml =
@"<meadinkent>
<record>
<comp_div>MENSWEAR</comp_div>
<sty_ret_type>ACCESSORIES</sty_ret_type>
<sty_pdt_type>BELTS</sty_pdt_type>
<pdt_category>AWESOME_BELTS</pdt_category>
</record>
</meadinkent>";
XDocument xDocument = XDocument.Parse(xml);
IEnumerable<XElement> selectedElements =
xDocument.XPathSelectElements(
"/meadinkent/record[comp_div='MENSWEAR' and sty_ret_type='ACCESSORIES']");
Assert.That(selectedElements.Count(), Is.EqualTo(1));
Assert.That(selectedElements.First().Name.LocalName, Is.EqualTo("record"));
}
Upvotes: 49
Reputation: 63378
You just need to have the and
ed list of conditions inside the [ ]
selector for record
:
/meadinkent/record[compdiv[.='MENSWEAR'] and sty_ret_type[.='ACCESSORIES']]
Reads as: under a top level meadinkent
node, a record
node, having a child compdiv
(with value MENSWEAR
) and a child sty_ret_rype
(with value ACCESSORIES
).
Upvotes: 7