使用XmlReader获取节点的XPath

本文关键字:XPath 节点 获取 XmlReader 使用 | 更新日期: 2023-09-27 18:02:16

如何获取当前XMLReader节点的XPath ?

例如:

<Employee>
    <Entity>
        <Id>1</Id>
    </Entity>
</Employee>

我需要得到1的XPath也就是Employee/Entity/Id。什么好主意吗?

using (var reader = XmlReader.Create(basePath, settings))
{
    while (reader.Read())
    {                   
        if (reader.NodeType == XmlNodeType.Text)
        {
            // need to get xpath of the text node
        }
        else if (reader.NodeType == XmlNodeType.Element)
        {
            // need to get xpath of the current node
        }
     }
 }

使用XmlReader获取节点的XPath

我的第一个建议是使用像LINQ to XML这样的高级API。使用像XmlReader这样的低级API的唯一原因是用于非常大的文件。使用LINQ to XML,简单的实现相当简单:

var doc = XDocument.Parse(xml);
foreach (var element in doc.Descendants())
{
    var path = element.AncestorsAndSelf().Select(e => e.Name.LocalName).Reverse();
    var xPath = string.Join("/", path);
}

使用XmlReader有点复杂,因为你必须在移动时跟踪元素路径:

using (var reader = XmlReader.Create(basePath, settings))
{
    var elements = new Stack<string>();
    while (reader.Read())
    {
        switch (reader.NodeType)
        {
            case XmlNodeType.Element:
                if(!reader.IsEmptyElement)
                    elements.Push(reader.LocalName);
                break;
            case XmlNodeType.EndElement:
                elements.Pop();
                break;
            case XmlNodeType.Text:
                path = string.Join("/", elements.Reverse());
                break;
        }
    }
}

下面是一个工作演示:https://dotnetfiddle.net/dpOzuL

请注意,虽然这适用于您的简单示例,但这是一个非常幼稚的XPath表达式创建,并不能在所有情况下工作(例如,当您有多个具有相同名称的兄弟或涉及名称空间时)。