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

时间:2022-08-11 16:52:10

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(水果),我想要得到那些有相同父母节点的。

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.

这是把所有的红色水果都还给我,而不仅仅是那些属于水果的水果。

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来实现这个?如何做呢?

3 个解决方案

#1


3  

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

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

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

#2


6  

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:

让我们看看/ and // /如何与根节点相关。当/在路径的开头使用:

/a

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

它将定义相对于根节点a的绝对路径。因此,在本例中,它将只在XML树的根上找到一个节点。

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

当//在路径的开始使用时:

//a

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

它将在XML文档的任何地方定义节点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 b that is an immediate direct descendant (ie. a child) of node a.

它将定义一个指向节点b的路径,它是直接的直系后代。节点a的子节点)。

When // used in the middle of a path:

当//在路径中间使用:

/a//b

it will define a path to node b that is ANY descendant of node a.

它将定义到节点b的路径,该路径是节点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.

//这将选择 元素的所有子元素。

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

如果 是根元素,则使用Xpath: /Fruits/Red_Fruits。[单斜杠/]

#3


1  

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;
    }

#1


3  

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

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

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

#2


6  

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:

让我们看看/ and // /如何与根节点相关。当/在路径的开头使用:

/a

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

它将定义相对于根节点a的绝对路径。因此,在本例中,它将只在XML树的根上找到一个节点。

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

当//在路径的开始使用时:

//a

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

它将在XML文档的任何地方定义节点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 b that is an immediate direct descendant (ie. a child) of node a.

它将定义一个指向节点b的路径,它是直接的直系后代。节点a的子节点)。

When // used in the middle of a path:

当//在路径中间使用:

/a//b

it will define a path to node b that is ANY descendant of node a.

它将定义到节点b的路径,该路径是节点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.

//这将选择 元素的所有子元素。

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

如果 是根元素,则使用Xpath: /Fruits/Red_Fruits。[单斜杠/]

#3


1  

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;
    }