XmlNode检查是否存在chidnodes列表

问题描述:

我想做一个函数,将采取一个XmlNode,并检查是否每个后续的孩子存在,我有问题。XmlNode检查是否存在chidnodes列表

的功能应该有类似

private string GetValueForNodeIfExists(XmlNode node, List<string> childNodes){...} 

一个例子说明我想完成什么签名: 我需要知道,如果一个节点的孩子(也可能是一个孩子的孩子)存在。 如果我有一个节点有一个名为“child”的子节点,并且“child”节点有一个名为“grandchild”的节点,并且该grandchild节点有一个名为“greatGrandchild”的节点,那么我想检查每个序列是否给出null还是不行,那么检查以下内容:

node['child'] != null 
node['child']['grandchild'] != null 
node['child']['grandchild']['greatGrandchild'] != null 

我检查的节点名称传递到函数作为List<string>其中索引关联到我检查节点的深度。例如,在上面的示例中,我将通过的列表是List<string> checkedasd = new List<String> {"child", "grandchild", "greatGrandchild" };

我不知道如何以编程方式追加每个['nodeName']表达式,然后执行表达式。如果我能弄明白这一点,我的策略是将所有东西都放在try块中,如果我发现了一个空异常,那么我会知道该节点不存在。

所有帮助表示赞赏

+0

是否每个节点必须直接后代? –

+0

如果您发现与您的模式匹配的多个结果会发生什么('IEnumerable '?) –

所有您需要do是使用XPath:

private string GetValueForNodeIfExists(XmlNode node, List<string> childNodes) 
{ 
    var xpath = string.Join("/", childNodes.ToArray()); 

    var foundNode = node.SelectSingleNode(xpath); 

    return foundNode != null ? foundNode.InnerText : null; 
} 

您还可以扩大你已经拥有并通过数值只是循环,直到你得到一个空值或到达终点:

private string GetValueForNodeIfExists(XmlNode node, List<string> childNodes) 
{ 
    foreach (var nodeName in childNodes) 
    { 
     if (node != null) 
     { 
      node = node[nodeName]; 
     } 
    } 

    return node != null ? node.InnerText : null; 
} 

我会用Linq2Xml和XPath

var childNodes = new List<string>() { "child", "grandchild", "greatGrandchild" }; 
var xpath = "//" + string.Join("/", childNodes); 

var xDoc = XDocument.Load(filename); 
var xElem = xDoc.XPathSelectElement(xpath); 

if(xElem!=null) //<--- No need for try- catch block 
    Console.WriteLine(xElem.Value); 

PS:我测试上面的代码的代码与下面的XML

<root> 
    <child> 
     <grandchild> 
      <greatGrandchild> 
       a 
      </greatGrandchild> 
     </grandchild> 
    </child> 
</root> 
+0

为什么在'XmlNode's已经允许使用XPath时使用Linq2Xml?这不符合OP的要求,因为它完全忽略了提供的'node'参数。 – JLRishe

+0

@JRRishe所以提出一种不同的方法在SO上是错误的?它是如此糟糕,我得到了downvote :) –

+0

不,但提供了一个错误的答案是。正如我已经表明的那样,你的回答并不是OP需要它做的。 – JLRishe

如果你没有结婚到XmlDocument的,并且可以使用Linq2Xml(或者想学习新的东西),另一种方法是:

DotNetFiddle

using System; 
using System.Xml; 
using System.Linq; 
using System.Xml.Linq; 
using System.Collections.Generic; 

public class Program 
{ 
    public static void Main() 
    { 
     //var xDoc = XDocument.Load(filename); 
     var XDoc = XDocument.Parse(@"<root><a><b><c>value</c></b></a><b><c>no</c></b><a><c>no</c></a></root>"); 
     Console.WriteLine("Params a b c "); 
     foreach(var nodeValue in XDoc.Root.GetValueForNodeIfExists("a", "b", "c")) 
     { 
      Console.WriteLine(nodeValue); 
     } 

     Console.WriteLine("List a b c "); 
     foreach(var nodeValue in XDoc.Root.GetValueForNodeIfExists("a", "b", "c")) 
     { 
      Console.WriteLine(nodeValue); 
     } 
    } 
} 


internal static class XElementExtensions 
{ 
    public static IEnumerable<string> GetValueForNodeIfExists(this XElement node, params string[] childNodesNames) 
    { 
     return GetValueForNodeIfExists(node, childNodesNames.ToList()); 
    } 

    public static IEnumerable<string> GetValueForNodeIfExists(this XElement node, IEnumerable<string> childNodesNames) 
    { 
     IEnumerable<XElement> nodes = new List<XElement> { node }; 

     foreach(var name in childNodesNames) 
     { 
      nodes = FilterChildrenByName(nodes, name); 
     } 

     var result = nodes.Select(n => n.Value); 

     return result; 
    } 

    private static IEnumerable<XElement> FilterChildrenByName(IEnumerable<XElement> nodes, string filterName) 
    { 
     var result = nodes 
      .SelectMany(n => n.Elements(filterName)); 

     Console.WriteLine("Filtering by {0}, found {1} elements", filterName, result.Count()); 

     return result;   
    } 
} 

结果:

PARAMS ABC

过滤由,发现2个元素

过滤用b,发现1个元素

过滤通过C,发现1个元素

列表abc

通过a筛选,找到2个元素

过滤用b,发现1个元素

过滤通过C,发现1个元素