用于查找没有特定属性的元素的XPath表达式

时间:2012-02-14 19:25:45

标签: c# xpath

我有一个xml文件,格式如下

<someXML>
    <a>
        <b></b>
        <b test='someValue'></b>
    </a>

    <c>
        <d test='someOtherValue'></d>
        <d></d>
    </c>
</someXML>

我正在尝试编写C#代码,它将为我提供一个仅包含具有test属性的节点的节点集。我试图以这种方式使用XPathExpression:

XDocument document = XDocument.Load("someXML");
XPathNavigator navigator = document.CreateNavigator();
XPathExpression expression = XPathExpression.Compile("//*[@test]");
object nodeSet = navigator.Evaluate(expression);

这似乎不起作用。调试时,nodeSet始终包含Root元素。表达式有问题或者这是否正常工作?

谢谢!

6 个答案:

答案 0 :(得分:4)

您是否认为nodeSet包含“Root”元素,因为调试器将其字符串表示形式显示为Position=0, Current={Root}?这可能会产生误导;出现“Root”元素的原因是因为XPathNodeIterator(在您的情况下由Evaluate返回的实际类型)尚未定位在查询产生的第一个节点上。根据{{​​3}}的MSDN文档:

  
    

XPathNodeIterator类返回的XPathNavigator对象不位于选定节点集中的第一个节点上。必须调用MoveNext类的XPathNodeIterator方法,将XPathNodeIterator对象放在所选节点集中的第一个节点上。

  

您可以通过迭代nodeSet

来检索您的路径项
XDocument document = XDocument.Load("someXML");
XPathNavigator navigator = document.CreateNavigator();
XPathExpression expression = XPathExpression.Compile("//*[@test]");
XPathNodeIterator nodeSet = (XPathNodeIterator)navigator.Evaluate(expression);
foreach (XPathItem item in nodeSet)
{
    // Process item here
}

或者,如果您希望将它们转换为数组:

XDocument document = XDocument.Load("someXML");
XPathNavigator navigator = document.CreateNavigator();
XPathExpression expression = XPathExpression.Compile("//*[@test]");
XPathNodeIterator nodeSet = (XPathNodeIterator)navigator.Evaluate(expression);
XPathItem[] items = nodeSet.Cast<XPathItem>().ToArray();

答案 1 :(得分:4)

您的XPath 确实有效,只需要稍微检索一下节点:

XPathNavigator navigator = document.CreateNavigator();
XPathExpression expression = XPathExpression.Compile("//*[@test]");
var matchedNodes = navigator.Select(expression);
foreach (XPathNavigator node in matchedNodes)
{
    Console.WriteLine(node.UnderlyingObject);
}

上面的代码段将打印以下内容:

<b test='someValue'></b>
<d test='someOtherValue'></d>

答案 2 :(得分:3)

你的表情似乎是正确的。但您可以使用XPathSelectElements扩展方法来简化:

var nodes = document.XPathSelectElements("//*[@test]");

答案 3 :(得分:2)

您的XPath查询是正确的。 Current成员将是Root元素(我不是XPathIterator专家,所以我真的不知道它背后的基本原理)。如果遍历nodeSet,则只能获得与XPath查询匹配的内容。所以我想答案是迭代集合并将每个项目放入集合中。

答案 4 :(得分:1)

我相信你会想要使用XPathNavigator对象的Select方法,而不是Evaluate,它将返回一个XPathNodeIterator对象。

http://msdn.microsoft.com/en-us/library/3tk3f03k.aspx

或者您可以使用XmlDocument对象和XmlNodeList:

        XmlDocument document = new XmlDocument();
        document.Load("somexml.xml");

        XmlNodeList nodeList = document.SelectNodes("//*[@test]");

        foreach (XmlNode Node in nodeList) { 
            // do something.            
        }

答案 5 :(得分:0)

为什么不这样做,假设您只是想要节点并且没有特定的理由使用导航器(null检查省略):

var document = XDocument.Load("someXML");
var myNodes = document.Descendants().Where(node => node.Attribute(myAttributeName) != null);

它不使用导航器,但如果您只是想要节点,那么它非常简单明了。