使用Linq to Xml处理带有Xml命名空间的内容

61

我有这段代码:

/*string theXml =
@"<Response xmlns=""http://myvalue.com""><Result xmlns:a=""http://schemas.datacontract.org/2004/07/My.Namespace"" xmlns:i=""http://www.w3.org/2001/XMLSchema-instance""><a:TheBool>true</a:TheBool><a:TheId>1</a:TheId></Result></Response>";*/

string theXml = @"<Response><Result><TheBool>true</TheBool><TheId>1</TheId></Result></Response>";

XDocument xmlElements = XDocument.Parse(theXml);

var elements = from data in xmlElements.Descendants("Result")
               select new {
                            TheBool = (bool)data.Element("TheBool"),
                            TheId = (int)data.Element("TheId"),
                          };

foreach (var element in elements)
{
    Console.WriteLine(element.TheBool);
    Console.WriteLine(element.TheId);
}

使用第一个Xml值时,结果为空,而使用第二个Xml值时,我有正确的值...

如何在Linq to Xml中使用xmlns值?

4个回答

96

LINQ to XML的方法,例如DescendantsElement,需要一个XName作为参数。自动进行从stringXName的转换。您可以通过在DescendantsElement方法中的字符串前添加XNamespace来解决此问题。请注意,此时有两个不同的命名空间。


string theXml = @"true1";
//将字符串解析为XDocument对象 XDocument xmlElements = XDocument.Parse( theXml );
//定义xml命名空间 XNamespace ns = "http://myvalue.com"; XNamespace nsa = "http://schemas.datacontract.org/2004/07/My.Namespace";
//查询XML元素 var elements = from data in xmlElements.Descendants( ns + "Result" ) select new { TheBool = (bool) data.Element( nsa + "TheBool" ), TheId = (int) data.Element( nsa + "TheId" ), };
//遍历查询结果并输出 foreach ( var element in elements ) { Console.WriteLine( element.TheBool ); Console.WriteLine( element.TheId ); }
该代码段是一个用于处理XML数据的C#代码示例。首先,它将包含XML数据的字符串解析为XDocument对象。然后,它定义了两个XML命名空间,并使用LINQ查询从XML文档中选择指定的元素。最后,它遍历查询结果并将其输出到控制台。

请注意在Descendants中使用了ns,而在Elements中使用了nsa。


22
xmlElements.Descendants(xmlElements.Root.GetDefaultNamespace() + "Result") 也可能有效... - O. Jones
另一个与.GetDefaultNamespace()对应的方法是.GetNamespaceOfPrefix(),适用于像<foo:Result xmlsns:foo="https://example.com"/>这样的XML。 - Robert K. Bell

27

你可以将带有命名空间的 XName 传递给 Descendants()Element()。当你向 Descendants() 传递一个字符串时,它会被隐式转换为没有命名空间的 XName。

要在命名空间中创建 XName,你需要创建一个 XNamespace,并将它与元素局部名称(一个字符串)连接起来。

XNamespace ns = "http://myvalue.com";
XNamespace nsa = "http://schemas.datacontract.org/2004/07/My.Namespace";

var elements = from data in xmlElements.Descendants( ns + "Result")
                   select new
                              {
                                  TheBool = (bool)data.Element( nsa + "TheBool"),
                                  TheId = (int)data.Element( nsa + "TheId"),
                              };

还有一种快捷方式可以通过从字符串进行隐式转换创建带有命名空间的 XName。

var elements = from data in xmlElements.Descendants("{http://myvalue.com}Result")
                   select new
                              {
                                  TheBool = (bool)data.Element("{http://schemas.datacontract.org/2004/07/My.Namespace}TheBool"),
                                  TheId = (int)data.Element("{http://schemas.datacontract.org/2004/07/My.Namespace}TheId"),
                              };

或者,您可以针对XElement进行查询。Name.LocalName

var elements = from data in xmlElements.Descendants()
                   where data.Name.LocalName == "Result"

我的智能感知中不存在LocalName。 - Tim
4
将“+”运算符转换为xname是毛骨悚然、可怕且彻头彻尾的灾难。微软当时在想什么?可能它在底层使用了Expression<Func<whatever>>,这让我感到不适。 - Gusdor

3

我有一个XML文档,在顶部列出了几个命名空间,我不太关心哪些元素来自哪个命名空间。我只想通过它们的名称获取这些元素。我写了这个扩展方法。

    /// <summary>
    /// A list of XElement descendent elements with the supplied local name (ignoring any namespace), or null if the element is not found.
    /// </summary>
    public static IEnumerable<XElement> FindDescendants(this XElement likeThis, string elementName) {
        var result = likeThis.Descendants().Where(ele=>ele.Name.LocalName==elementName);
        return result;
    }

0
我发现以下代码在VB.NET中读取有命名空间的属性方面是有效的:
MyXElement.Attribute(MyXElement.GetNamespaceOfPrefix("YOUR_NAMESPACE_HERE") + "YOUR_ATTRIB_NAME")

希望这能对某人有所帮助。

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