【问题标题】:Get the XPath of every node that contains a specific attribute using XmlReader?使用 XmlReader 获取包含特定属性的每个节点的 XPath?
【发布时间】:2016-05-21 11:03:04
【问题描述】:

我有一个可能看起来像这样的变量 XML:

<content>
    <main editable="true">
        <h1>Here is my header</h1>
        <p>Here is my content</p>
    </main>
    <buttons>
        <positive editable="true">I agree!</positive>
        <negative editable="true">No - get me outta here!</negative>
    </button>
</content>

我想获取所有具有“可编辑”属性等于“真”的节点的 XPath。请注意,属性可以处于可变节点级别,因此我不能只在一个级别遍历所有节点并检查属性。由于速度的原因,我也想使用 XmlReader,但如果有更好/更快的方法,那么我也愿意。

var xml = IO.File.ReadAllText(contentFilePath);
var readXML = XmlReader.Create(new StringReader(xml));

readXML.ReadToFollowing("content");

while (readXML.Read()) {
    //???
}

【问题讨论】:

  • 如果您将所有文本读取到一个字符串中,我认为您将失去 XmlReader 的主要好处...
  • @Jacob 嗯,很高兴知道。如果文件在文件系统上,最快的方法是什么?读取字节并提供流?
  • @RichC 您的文件有多大?除非它们非常很大,否则性能优势可能不值得。
  • XmlReader 不会公开父堆栈,因此您必须在阅读器进出元素时创建自己的下推堆栈。作为替代方案,读入XElement,然后执行stackoverflow.com/questions/451950/get-the-xpath-to-an-xelement
  • 另外,您是要构造一个绝对 XPath 表达式字符串 from 元素,还是要弄清楚如何选择所有可编辑属性设置为 true 的节点使用 XPath? (对不起,如果这只是我糟糕的英语解释)

标签: c# .net xml xmlreader


【解决方案1】:

感谢大家的反馈,我使用此代码作为我的解决方案:

Dim xml = IO.File.ReadAllText(masterLangDir)
Dim xdoc = New XmlDocument()
xdoc.LoadXml(xml)
Dim xPaths = findAllNodes(xdoc.SelectSingleNode("content"), New List(Of String))

public List<string> findAllNodes(XmlNode node, List<string> xPaths)
{
    foreach (XmlNode n in node.ChildNodes) {
        var checkForChildNodes = true;
        if (n.Attributes != null) {
            if (n.Attributes("editable") != null) {
                if (n.Attributes("editable").Value == "true") {
                    xPaths.Add(GetXPathToNode(n));
                    checkForChildNodes = false;
                }
            }
        }
        if (checkForChildNodes) {
            xPaths = findAllNodes(n, xPaths);
        }
    }
    return xPaths;
}

public string GetXPathToNode(XmlNode node)
{
    if (node.NodeType == XmlNodeType.Attribute) {
        // attributes have an OwnerElement, not a ParentNode; also they have             
        // to be matched by name, not found by position             
        return String.Format("{0}/@{1}", GetXPathToNode(((XmlAttribute)node).OwnerElement), node.Name);
    }
    if (node.ParentNode == null) {
        // the only node with no parent is the root node, which has no path
        return "";
    }

    // Get the Index
    int indexInParent = 1;
    XmlNode siblingNode = node.PreviousSibling;
    // Loop thru all Siblings
    while (siblingNode != null) {
        // Increase the Index if the Sibling has the same Name
        if (siblingNode.Name == node.Name) {
            indexInParent += 1;
        }
        siblingNode = siblingNode.PreviousSibling;
    }

    // the path to a node is the path to its parent, plus "/node()[n]", where n is its position among its siblings.         
    return String.Format("{0}/{1}[{2}]", GetXPathToNode(node.ParentNode), node.Name, indexInParent);
}

I picked up the GetXPathToNode function from this thread.

【讨论】:

    猜你喜欢
    • 2015-09-29
    • 1970-01-01
    • 1970-01-01
    • 2010-11-30
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多