C# LINQ和XML获取子节点

3

遇到了获取节点值的问题。不确定为什么以下代码无法实现。

<?xml version="1.0" encoding="utf-8"?>
<?xml-stylesheet type='text/xsl' href='STIG_unclass.xsl'?>
<Benchmark xmlns:dsig="http://www.w3.org/2000/09/xmldsig#" xmlns:xhtml="http://www.w3.org/1999/xhtml" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:cpe="http://cpe.mitre.org/language/2.0" xmlns:dc="http://purl.org/dc/elements/1.1/" id="Windows_7_STIG" xml:lang="en" xsi:schemaLocation="http://checklists.nist.gov/xccdf/1.1 http://nvd.nist.gov/schema/xccdf-1.1.4.xsd http://cpe.mitre.org/dictionary/2.0 http://cpe.mitre.org/files/cpe-dictionary_2.1.xsd" xmlns="http://checklists.nist.gov/xccdf/1.1">
    <status date="2015-06-16">accepted</status>
    <title>Windows 7 Security Technical Implementation Guide</title>
    <description>
        The Windows 7 Security Technical Implementation Guide (STIG) is published as a tool to improve the security of Department of Defense (DoD) information systems.  The requirements were developed from DoD consensus, as well as the Windows 7 Security Guide and security templates published by Microsoft Corporation.  Comments or proposed revisions to this document should be sent via e-mail to the following address:  disa.stig_spt@mail.mil.
    </description>
    <notice id="terms-of-use" xml:lang="en">Developed_by_DISA_for_the_DoD</notice>
    <reference href="http://iase.disa.mil">
        <dc:publisher>DISA, Field Security Operations</dc:publisher>
        <dc:source>STIG.DOD.MIL</dc:source>
    </reference>
    <plain-text id="release-info">Release: 20 Benchmark Date: 24 Jul 2015</plain-text>
</Benchmark>

示例 XML 文件。

以下是我的代码。

String Title = LoadedXML.Element("Benchmark").Attribute("id").Value;
var XMLData = LoadedXML.Element("Benchmark").Elements("plain-text")
                 .Single(release => release.Attribute("id").Value == "release-info").Value;

有没有一种方法可以同时获取多个节点的值?例如,可以同时获取标题和发布日期,而不是每次分别获取。


你的第一个 Benchmark 元素缺少闭合引号。这只是问题中的笔误吗? - Steve
1
如果你需要使用 XML 中的多个值,为什么不直接将它反序列化成一个类呢?有特别的原因吗? - Pierre-Luc Pineault
如果您使用linq-to-xml,您将编写“查询”来过滤并获取所需的单个内容。如果您正在获取大量信息,则可能应该反序列化和映射(例如使用automapper)到所需的对象。 - Arghya C
我想我需要看一下反序列化。因为最终我需要加载文件中的所有数据。而且它很大。你能推荐一些好的资源吗? - Zach Schulze
@Steve 是的,这是一个笔误。对此我感到抱歉。 - Zach Schulze
@ZachSchulze 看看这个答案是否有帮助。 - Arghya C
2个回答

1
你的代码失败是因为你的XML包含命名空间,无法直接访问节点。如果要确认,请查询LoadedXML.Elements()并在调试器中检查其值,你可以清楚地看到命名空间:-

enter image description here

因此,您需要声明命名空间并使用它:-
XNamespace ns = "http://checklists.nist.gov/xccdf/1.1";

如果您想同时获取两个值,可以将其投影到一个匿名类型中,如下所示:
var result = LoadedXML.Root.Elements(ns + "plain-text")
                      .Where(x => (string)x.Attribute("id") == "release-info")
                      .Select(x => new
                             {
                                 Title = (string)x.Document.Root.Attribute("id"),
                                 XMLData = x.Value
                             }).FirstOrDefault();

这个查询给我以下的输出:

enter image description here


1
Linq-to-xml通常用于查询XML以过滤其节点,然后根据需要获取所需的元素/值。它更像是使用SQL查询表格。如果需要作为结果返回所有/大部分XML,则更好的方法是将XML反序列化为本地(在此处为C#)对象,并将其映射到所需的模型对象。XML始终可以被视为对象的序列化版本(尽管也可以手动执行),并且可以反序列化回实际对象。.Net对所有这些都有本机支持,请参阅msdn链接XML SerializationDeserialization以获取详细信息。您可以编写一个小方法来反序列化您的对象,如下所示。
using System.Xml.Linq;
using System.Xml.Serialization;

public class XMLHelper
{
    public T DeserializeData<T>(string data)
    {
        XmlSerializer serializer = new XmlSerializer(typeof(T));
        StringReader reader = new StringReader(data);
        var deserializedObject = serializer.Deserialize(reader);
        return deserializedObject == null ? default(T) : (T)deserializedObject;
    }
}

为了获取字符串,您可以像这样做:File.ReadAllText(xmlFilePath)或者任何更容易的方式。这将给您整个XML的反序列化对象。如果您想要其他转换后的对象,您可以手动映射它,或使用AutoMapper

我一定会研究这个问题。由于文件很大,需要多次访问,因此我需要进一步了解如何在反序列化后准确访问XML的各个部分。我猜想将其放入DataSet中?然后访问表格?但是我怎么知道要访问哪个表格呢? - Zach Schulze
反序列化后,您将得到一个普通的 C# 对象。因此,您可以像使用任何其他对象一样使用它。 - Arghya C

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接