【问题标题】:C# Get Xelement Attribute Value by Attribute NameC# 通过属性名称获取 Xelement 属性值
【发布时间】:2016-08-27 14:37:39
【问题描述】:

我正在尝试在下面的 xml 代码中获取 operating-system 属性的值,但在我尝试过的所有解决方案中,从堆栈、dotnetcurry 和 Microsoft 至今,我都得到了 NullPointerExecption 或它只是不返回任何值。

这是我要解析的 xml 数据:

<Report name="Black Workstation" xmlns:cm="http://www.nessus.org/cm">
  <ReportHost name="192.168.1.000>
    <HostProperties>
        <tag name="HOST_END">Wed Jun 29 10:32:54 2016</tag>
        <tag name="LastAuthenticatedResults">1467214374</tag>
        <tag name="patch-summary-total-cves">5</tag>
        <tag name="cpe">cpe:/o:microsoft:windows</tag>
        <tag name="operating-system">Microsoft Windows 7 Enterprise Service Pack 1</tag>
    </HostProperties>
  </ReportHost>
</Report>

我尝试了很多方法,但这里是最后两种:

XNamespace ns = "http://www.nessus.org/cm";
var operatingSystem = (findings.Where(a => a.Attribute("name").Value == "operating-system")
.Select(a => a.Value));                                        

var operatingSystem = findings.Descendants().Where(x => x.Attribute("name").Value == ns + "operating-system");

也试过这个解决方案:Use Linq to Xml with Xml namespaces

我在 Microsoft 教程中有这个方法,但它只返回 true/false,我无法对其进行操作,以便将值 Microsoft Windows 7 Enterprise Service Pack 1 分配给 os 变量。

XElement xelement = XElement.Load(s);
IEnumerable<XElement> findings = xelement.Elements();

var hostProperties = from hp in findings.Descendants("HostProperties")
                     select new
                     {
                         os = (string)hp.Element("tag").Attribute("name").Value == "operating-system",
                     };

我尝试过使用上面的where 子句使用各种其他Linq-to-Xml 查询,但它们都返回Nullno values to enumerate

【问题讨论】:

  • 顺便说一句——这个问题的提出真的很好。提供相关数据以进行尝试,您没有得到什么以及您尝试过的内容:)随着时间的推移得到改善:)

标签: c# xml linq linq-to-xml xml-namespaces


【解决方案1】:

在您的情况下,您不需要应用命名空间:

var result = XDocument.Load("data.xml")
                      .Descendants("tag")
                      .Where(e => e.Attribute("name").Value == "operating-system")
                      .FirstOrDefault()?.Value;

 //result = Microsoft Windows 7 Enterprise Service Pack 1

深入了解here,您实际上可以看到,即使您在 xml 中定义了命名空间,您的任何元素都没有使用它。您定义的命名空间 (xmlns:cm) 仅适用于带有 cm: 前缀的元素,它们不属于它们。

如果我将您的 xml 更改如下(命名空间仅适用于 xmlns 而不是 xmlns:cm),请查看:

<Report name="Black Workstation" xmlns="http://www.nessus.org/cm"> 
  <ReportHost name="192.168.1.000">
  <HostProperties>
    <tag name="HOST_END">Wed Jun 29 10:32:54 2016</tag>
    <tag name="LastAuthenticatedResults">1467214374</tag>
    <tag name="patch-summary-total-cves">5</tag>
    <tag name="cpe">cpe:/o:microsoft:windows</tag>
    <tag name="operating-system">Microsoft Windows 7 Enterprise Service Pack 1</tag>
  </HostProperties>
</ReportHost>
</Report>

上面的代码会返回null,你必须这样写:

XNamespace ns = "http://www.nessus.org/cm";
var result = XDocument.Load("data.xml")
                      .Descendants(ns + "tag")
                      .Where(e => e.Attribute("name").Value == "operating-system")
                      .FirstOrDefault()?.Value;

【讨论】:

  • 在没有FirstorDefault() 的情况下还有其他方法吗?不管是不是第一次,它只选择那里的任何东西?
  • @Chris - FirstOrDefault() 只是为了从集合中取出一项 - 该集合在任何情况下都只包含一项 -> 5 个标记元素中只有 1 个与 where 子句匹配。您也可以使用ToList()[0].Value,但我认为FirstOrDefault()?.Value 是处理极端情况的更好方法
【解决方案2】:

请尝试以下方法

 XDocument document = XDocument.Load("content.xml");
 var name = document.XPathSelectElement("Report/ReportHost/HostProperties/tag[@name='operating-system']").Value;

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 2012-11-17
    • 1970-01-01
    • 1970-01-01
    • 2013-07-21
    • 1970-01-01
    • 1970-01-01
    • 2013-01-02
    • 1970-01-01
    相关资源
    最近更新 更多