获取 XML 的 XElement

Posted

技术标签:

【中文标题】获取 XML 的 XElement【英文标题】:Get the XElement for the XML 【发布时间】:2012-02-24 04:09:33 【问题描述】:

这是我的 XML 文件:

<Applications>
   <Application Name="Abc">
     <Section Name="xyz">
        <Template Name="hello">
         ...
         ....
         </Template>
      </Section>
   </Application>
   <Application Name="Abc1">
     <Section Name="xyz1">
        <Template Name="hello">
         ...
         ....
         </Template>
      </Section>
   </Application>

我需要做的是根据模板标签的名称属性从给定的结构中获取模板 XElement。问题是可以有多个具有相同属性名称的模板标签。区分因素是Application Name属性值和section属性值。

目前我可以通过首先根据其属性获取应用程序元素,然后根据其属性获取部分,最后根据其名称获取模板来获取 XElement。

我想知道有没有办法一次性搞定。

【问题讨论】:

您可能可以通过构建和评估 XPath 表达式来实现这一点,但使用 LINQ to XML 和您当前的方法也是一种有效、高效的策略。您是否有特殊原因要“一次性”匹配元素? 没有特别的原因,只是想知道是否有可能完成它。 【参考方案1】:

我会使用您可以调用Elements 或现有序列的事实,所以:

var template = doc.Descendants("Application")
                  .Where(x => (string) x.Attribute("Name") == applicationName)
                  .Elements("Section")
                  .Where(x => (string) x.Attribute("Name") == sectionName)
                  .Elements("Template")
                  .Where(x => (string) x.Attribute("Name") == templateName)
                  .FirstOrDefault();

您甚至可能想在某处添加扩展方法:

public static IEnumerable<XElement> WithName(this IEnumerable<XElement> elements,
                                             string name)

    this elements.Where(x => (string) x.Attribute("Name") == name);

然后你可以将查询重写为:

var template = doc.Descendants("Application").WithName(applicationName)
                  .Elements("Section").WithName(sectionName)
                  .Elements("Template").WithName(templateName)
                  .FirstOrDefault();

...我想你会同意它的可读性很强:)

请注意,使用将XAttribute 强制转换为string 而不是使用Value 属性意味着任何没有Name 属性的元素都会被有效地忽略,而不是导致NullReferenceException

【讨论】:

扩展方法的整洁和 +1,不知道这一点。谢谢【参考方案2】:

下面的代码应该可以解决问题:

var template = doc.Descendants("Template")
                  .Where(x => x.Attribute("Name").Value == "hello"
                           && x.Parent.Attribute("Name").Value == "xyz1"
                           && x.Parent.Parent.Attribute("Name").Value == "Abc1");

请注意,如果 XML 不符合规范,此代码将引发异常。具体来说,如果有问题的任何标签不包含名为“名称”的属性,则会有一个NullReferenceException。或者如果模板标签没有两级父级。

【讨论】:

像魅力一样工作,在末尾添加了 FirstOrDefault()。【参考方案3】:
    XDocument doc = XDocument.Load("Path of xml");
    var selection =
        doc.Descendants("Section").Select(item => item).Where(
            item => item.Attribute("Name").Value.ToString().Equals("Section Name Value")).ToList();

    if(null != selection)
    
        var template =
            selection.Descendants("Template").Select(item => item).Where(
            item => item.Attribute("Name").Value.ToString().Equals("Template name value"));
    

【讨论】:

我还没有尝试你的答案,我会尽快回复。【参考方案4】:

XPath 应该可以帮助您。使用Extensions.XPathSelectElement Method (XNode, String):

XDocument xdoc = XDocument.Load("yourfile.xml");
string xPathQuery = string.Format(
    "/Applications/Application[@Name='0']/Section[@Name='1']/Template[@Name='2']",
    "MyApplication",
    "MySection",
    "MyTemplate"
);

XElement template = xdoc.Root.XPathSelectElement(xPathQuery);

【讨论】:

由于节点的层次结构是已知的,我宁愿使用 xDoc.XPathSelectElements("/Applications/Application/Section/Template[@Name='" + templateName+ "']" ); 应该更高效 @nulltoken:这不符合 OP 的要求。 @DanielHilgarth 你是对的。我确实 忘记为ApplicationSection 添加命名限制。我的观点是宁愿使用从根目录开始的显式路径,而不是“//template[@Name='xxxx']”查询。但是,看起来答案已经确定了:) 是的,我第一次看错了这个问题。我已经以这种方式更新了我的答案。

以上是关于获取 XML 的 XElement的主要内容,如果未能解决你的问题,请参考以下文章

C#获取xml值的问题

怎样获取xml中当前节点的直接孩子节点个数

GroovyXml 反序列化 ( 使用 XmlParser 解析 Xml 文件 | 获取 Xml 文件中的节点和属性 | 获取 Xml 文件中的节点属性 )

java获取XML指定节点的全部子节点

xml带冒号属性怎么获取

XML(php中获取xml文件的方式/ajax获取xml格式的响应数据的方式)