使用XPath根据多个条件进行选择

29

我有一个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>
<medinkent>

我想使用XPath选择匹配所有四个元素的节点,但我在尝试正确的布尔语法时遇到了困难。我正在尝试这个来匹配前两个作为测试:

"/meadinkent/record/comp_div[.='" & comp_div & "'] and /meadinkent/record/sty_ret_type[.='" & sty_ret_type & "']"

这里出错了,它说没有返回节点。显然我非常愚蠢 - 我做错了什么?

谢谢, mAtt

3个回答

48

Union(并集)
为了获取两个节点,需要使用并集运算符- |

例如,下一个查询将返回两种类型的节点- comp_divsty_ret_type

/meadinkent/record/comp_div | /meadinkent/record/sty_ret_type

按子节点值筛选
为了根据其子节点的值筛选节点,您需要将所有条件放在同一括号中[nodeA='value1' and nodeB='value2']

例如,下一个查询将返回其子节点与过滤器匹配的记录节点:

/meadinkent/record[comp_div='MENSWEAR' and sty_ret_type='ACCESSORIES']

一个C#联合体示例:
[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));
}

一个关于使用子节点过滤的C#示例:
[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"));
}

抱歉,我没有表述清楚。我要的是指向匹配所有元素值的Record节点的引用。因此,如果我想断言sty_pdt_type为“BELTS”且pdt_category为“AWESOMEBELTS”,我希望有一个引用,指向所有记录节点,其中这些元素与这些值匹配。 - Bob Tway
@Matt Thrower,我现在明白你的意思了 :) 已经相应地更新了答案。 - Elisha

7
你只需要将条件列表 [ ] 嵌套在 record 选择器内用and连接即可:
/meadinkent/record[compdiv[.='MENSWEAR'] and sty_ret_type[.='ACCESSORIES']]

读作:在顶层 meadinkent 节点下,有一个 record 节点,它有一个子节点 compdiv(其值为 MENSWEAR 一个子节点 sty_ret_rype(其值为 ACCESSORIES)。

1

或者您可以使用 LINQ to XML 并像这样执行:

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;

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接