【问题标题】:How to get all XML nodes with the same name without knowing their level?如何在不知道级别的情况下获取所有同名的 XML 节点?
【发布时间】:2013-07-16 11:01:24
【问题描述】:

我有一个 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 文件,所以我不知道特定节点的确切名称,我只需要将所有具有相同名称和相同级别的节点放入一个XmlNodeList 使用C#语言

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

【问题讨论】:

  • 你真的一试便知吗?我不这么认为
  • 为什么限制“不使用 LINQ”?我要做的是将你所拥有的结果按深度分组,然后选择你想要的组。
  • 基本上,我不认为你可以实现“所有标签的深度相同”,而不回答“与什么深度相同”的问题?
  • 我无法使用 LINQ,因为我的 vs 版本是 2005 :/
  • @IAbstract 旧 VS 版本不支持新版本中的语言功能。类似于 LINQ 的扩展方法。

标签: c# xml .net-3.0


【解决方案1】:

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

让我们看看/// 是如何与根节点相关的。当/ 用于路径开头时:

/a

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

// 用于路径开头时:

//a

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

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

/a/b

它将定义到节点 b 的路径,该路径是节点 a 的直接后代(即子节点)。

// 用于路径中间时:

/a//b

它将定义到节点b 的路径,该路径是节点aANY 后代。

回到你的问题:

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

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

//使用SelectNodes()方法

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

// 这将选择所有属于&lt;Fruits&gt; 元素的子元素。

如果 &lt;Fruits&gt; 是根元素,请使用 Xpath:/Fruits/Red_Fruits。 [单斜线/]

【讨论】:

    【解决方案2】:

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

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

    【讨论】:

    • 这正是我所需要的,这条简单的线: XmlNodeList list = current.ParentNode.SelectNodes(current.Name);工作得很好。
    • 将测试您和其他人提供的其他解决方案,但提前非常感谢。
    【解决方案3】:

    在最坏的情况下,您可以循环浏览 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;
        }
    

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2011-01-24
      • 1970-01-01
      • 2012-07-21
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多