我正在尝试创建一个带有XmlNode的函数,并检查每个后续子节点是否存在并且遇到问题。
该函数应具有类似于
的签名private string GetValueForNodeIfExists(XmlNode node, List<string> childNodes){...}
说明我想要完成的内容的示例: 我需要知道节点的孩子(可能还有孩子的孩子)是否存在。 如果我有一个节点,其中有一个名为“child”的子节点,而“child”节点有一个名为“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块中,如果我发现了Null异常,那么我就知道节点不存在。
感谢所有帮助
答案 0 :(得分:4)
我会使用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>
答案 1 :(得分:1)
如果您未与XmlDocument结婚并且可以使用Linq2Xml(或想要学习新内容),则另一种选择可能是:
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 a b c
按a过滤,找到2个元素
按b过滤,找到1个元素
按c过滤,找到1个元素
值
列出b c
按a过滤,找到2个元素
按b过滤,找到1个元素
按c过滤,找到1个元素
值
答案 2 :(得分:0)
您需要做的就是使用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;
}