10

我有一个 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>

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

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

这是我现在使用 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");
    } 
 }

这会将所有 red_fruits 归还给我,而不仅仅是属于 Fruits 的那些。

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

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

4

3 回答 3

17

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

让我们看看与根节点相关的方式/和工作方式。///在路径的开头使用:

/a

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

//在路径的开头使用:

//a

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

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

/a/b

它将定义指向 node 的路径,该路径是 nodeb的直接后代(即孩子)a

//路径中间使用时:

/a//b

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

回到你的问题:

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

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

//使用SelectNodes()方法

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

// 这将选择该元素的所有子<Fruits>元素。

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

于 2013-07-17T19:07:09.120 回答
3

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

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

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

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

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

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

XmlNodeList list = current.ParentNode.SelectNodes(current.Name);
于 2013-07-17T18:56:18.680 回答
1

在最坏的情况下,您可以循环浏览 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;
    }
于 2013-07-17T19:01:38.327 回答