C# 如何在不知道它们的级别的情况下获取所有具有相同名称的 XML 节点?

声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow 原文地址: http://stackoverflow.com/questions/17707466/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me): StackOverFlow

提示:将鼠标放在中文语句上可以显示对应的英文。显示中英文
时间:2020-08-10 10:16:30  来源:igfitidea点击:

How to get all XML nodes with the same name without knowing their level?

c#xml.net-3.0

提问by Rafael Vega?as

I have a XML Example:

我有一个 XML 示例:

<Fruits>
    <Red_fruits>
        <Red_fruits></Red_fruits>
    </Red_fruits>
    <Yellow_fruits>
        <banana></banana>
    </Yellow_fruits>
    <Red_fruits>
        <Red_fruits></Red_fruits>
    </Red_fruits>
</Fruits>

I have 4 Red_fruits tags, 2 of them shares the same ParentNode (Fruits), I want to get those which have the same ParentNode.

我有 4 个 Red_fruits 标签,其中 2 个共享相同的 ParentNode(水果),我想获得那些具有相同 ParentNode 的标签。

But I just want those which have the same name (Red_fruits), which means Yellow_fruits tag isn't included.

但我只想要那些具有相同名称的 (Red_fruits),这意味着不包括 Yellow_fruits 标签。

This is the way I am doing right now using C# language:

这是我现在使用 C# 语言的方式:

XmlDocument doc = new XmlDocument();
string selectedTag = cmbX.text;

if (File.Exists(txtFile.text))
{
    try
    {
        //Load
        doc.Load(cmbFile.text);

        //Select Nodes
        XmlNodeList selectedNodeList = doc.SelectNodes(".//" + selectedTag);
    }
    Catch
    {
        MessageBox.show("Some error message here");
    } 
 }

This is returning me all red_fruits, not just the ones that belongs to Fruits.

这将返回所有 red_fruits,而不仅仅是属于 Fruits 的那些。

I can't make XmlNodeList = doc.SelectNodes("/Fruits/Red_fruits") because I want to use this code to read random XML files, so I don't know the exact name that specific node will have, I just need to put all nodes with the same name and same level into a XmlNodeList using C# Language.

我不能使 XmlNodeList = doc.SelectNodes("/Fruits/Red_fruits") 因为我想使用此代码读取随机 XML 文件,所以我不知道特定节点将具有的确切名称,我只需要使用 C# 语言将所有具有相同名称和相同级别的节点放入一个 XmlNodeList 中。

Is there a way of achieve this without using LINQ? How to do that?

有没有办法在不使用 LINQ 的情况下实现这一目标?怎么做?

采纳答案by Sam I am says Reinstate Monica

If you're simply trying to find the "next" or "previous" iteration of a single node, you can do the following and then compare it to the name

如果您只是想查找单个节点的“下一个”或“上一个”迭代,则可以执行以下操作,然后将其与名称进行比较

XmlNode current = doc.SelectSingleNode("Fruits").SelectSingleNode("Red_fruits");

XmlNode previous = current.NextSibling;
XmlNode next = current.NextSibling;

and you can iterate until you find the proper sibling

你可以迭代直到找到合适的兄弟

while(next.Name != current.Name)
{
    next = next.NextSibling;
}

or you can even get your list by invoking the 'Parent' property

或者您甚至可以通过调用“父”属性来获取您的列表

XmlNodeList list = current.ParentNode.SelectNodes(current.Name);

回答by Ted

Worst case scenario, you can cycle through the XMLNode items in selectedNodeList and check the ParentNode properties. If necessary you could go recursive on the ParentNode check and count the number of times it takes to get to the root node. This would give you the depth of a node. Or you could compare the ParentNode at each level to see if it is the parent you are interested in, if that parent is not the root.

最坏的情况是,您可以循环浏览 selectedNodeList 中的 XMLNode 项并检查 ParentNode 属性。如有必要,您可以递归检查 ParentNode 并计算到达根节点所需的次数。这将为您提供节点的深度。或者您可以比较每个级别的 ParentNode 以查看它是否是您感兴趣的父节点,如果该父节点不是根节点。

    public void Test(){


        XmlDocument doc = new XmlDocument();
        string selectedTag = cmbX.text;

        if (File.Exists(txtFile.text))
        {
            try
            {
                //Load
                doc.Load(cmbFile.text);

                //Select Nodes
                XmlNodeList selectedNodeList = doc.SelectNodes(".//" + selectedTag);
                List<XmlNode> result = new List<XmlNode>();
                foreach(XmlNode node in selectedNodeList){
                    if(depth(node) == 2){
                        result.Add(node);
                    }
                }
                // result now has all the selected tags of depth 2
            }
            Catch
            {
                MessageBox.show("Some error message here");
            } 
        }

    }

    private int depth(XmlNode node) {
        int depth = 0;
        XmlNode parent = node.ParentNode;
        while(parent != null){
            parent = node.ParentNode;
            depth++;
        }
        return depth;
    }

回答by R.C

An understanding on the usage of Single Slash /and Double slash //can help here.

了解单斜杠/和双斜杠的用法在//这里会有所帮助。

Let's see how /and //work in relation to the root node. When /is used at the beginning of a path:

让我们看看如何///工作有关的根节点。When/用于路径的开头:

/a

it will define an absolute path to node arelative to the root. As such, in this case, it will only find anodes at the root of the XML tree.

它将定义一个a相对于根节点的绝对路径。因此,在这种情况下,它只会a在 XML 树的根部找到节点。

When //is used at the beginning of a path:

When//用于路径的开头:

//a

it will define a path to node aanywhere within the XML document. As such, in this case, it will find anodes located at any depth within the XML tree.

它将定义指向aXML 文档中任何位置的节点的路径。因此,在这种情况下,它将查找a位于 XML 树中任何深度的节点。

These XPath expressions can also be used in the middle of an XPath value to define ancestor-descendant relationships. When /is used in the middle of a path:

这些 XPath 表达式也可以用在 XPath 值的中间来定义祖先-后代关系。当/在路径中间使用时:

/a/b

it will define a path to node bthat is an immediate direct descendant (ie. a child) of node a.

它将定义一个到 node 的路径,该路径是 nodeb的直接后代(即子代)a

When //used in the middle of a path:

//路径中间使用时:

/a//b

it will define a path to node bthat is ANYdescendant of node a.

它将定义一个指向 node 的路径,该路径是 nodeb任何后代a

Coming back to your question:

回到你的问题:

// using GetElementsByTagName()return all the Elements having name: Red_Fruits

// 使用GetElementsByTagName()返回所有具有名称的元素:Red_Fruits

XmlDocument doc = new XmlDocument();
XmlNodeList nodes= doc.GetElementsByTagName("Red_Fruits"); 

//Using SelectNodes()method

//使用SelectNodes()方法

XmlNodelist nodes = doc.SelectNodes("//Fruits/Red_Fruits"); 

// This will select all elements that are children of the <Fruits>element.

// 这将选择作为元素子元素的所有元素<Fruits>

In case <Fruits>is the root element use the Xpath: /Fruits/Red_Fruits. [ a single slash /]

如果<Fruits>是根元素,请使用 Xpath: /Fruits/Red_Fruits。[单斜线/]