无需不断指定默认命名空间即可解析 XDocument

15

我有一些XML数据(类似于下面的示例),我想在代码中读取其中的值。

为什么我被迫指定默认命名空间以访问每个元素?我本来希望默认命名空间适用于所有元素。

是否有更合理的方法来实现我的目标?

示例XML:

<?xml version="1.0" encoding="UTF-8"?>
<ReceiptsBatch xmlns="http://www.secretsonline.gov.uk/secrets">
    <MessageHeader>
        <MessageID>00000173</MessageID>
        <Timestamp>2009-10-28T16:50:01</Timestamp>
        <MessageCheck>BX4f+RmNCVCsT5g</MessageCheck>
    </MessageHeader>
    <Receipts>
        <Receipt>
            <Status>OK</Status>
        </Receipt>
    </Receipts>
</ReceiptsBatch>

读取我需要的 XML 元素的代码:

XDocument xDoc = XDocument.Load( FileInPath );

XNamespace ns = "http://www.secretsonline.gov.uk/secrets";

XElement MessageCheck = xDoc.Element(ns+ "MessageHeader").Element(ns+"MessageCheck");
XElement MessageBody = xDoc.Element("Receipts");

逻辑上,为每个元素指定命名空间是正确的方式。仅仅因为你不必在每个元素中重复声明 xmlns,并不意味着子元素位于默认命名空间 (xmlns="") 中。 - dtb
1
有没有可能清除默认命名空间,以免我不得不在每个元素名称前添加“ns+”? - TeamWild
5个回答

9

此答案所建议的那样,您可以通过从内存副本中删除所有命名空间来实现此功能。我想这只有在您知道结果文档中不会存在名称冲突时才应这样做。

/// <summary>
/// Makes parsing easier by removing the need to specify namespaces for every element.
/// </summary>
private static void RemoveNamespaces(XDocument document)
{
    var elements = document.Descendants();
    elements.Attributes().Where(a => a.IsNamespaceDeclaration).Remove();
    foreach (var element in elements)
    {
        element.Name = element.Name.LocalName;

        var strippedAttributes =
            from originalAttribute in element.Attributes().ToArray()
            select (object)new XAttribute(originalAttribute.Name.LocalName, originalAttribute.Value);

        //Note that this also strips the attributes' line number information
        element.ReplaceAttributes(strippedAttributes.ToArray());
    }
}

7
您可以使用XmlTextReader.Namespaces属性在读取XML文件时禁用命名空间。
string filePath;
XmlTextReader xReader = new XmlTextReader(filePath);
xReader.Namespaces = false;
XDocument xDoc = XDocument.Load(xReader);

如果您已经将XML作为字符串读取,那该怎么办呢?XmlDocument只有Parse方法能够接受字符串作为参数,而您需要做很多工作,将字符串转换为可用于XReader的流。 - Artem A

3

这就是Linq-To-Xml的工作原理。如果元素不在默认命名空间中,你将无法找到它,后代元素也是如此。摆脱命名空间最快的方法是从初始XML中删除与命名空间的链接。


默认命名空间不是通过定义xmlns="someNamespace"在XDocument中定义的吗?当您编写XML的文本版本时,无需指定默认命名空间,因此我不希望在代码中这样做。 - TeamWild

1
请注意,元素Receipts也在命名空间http://www.secretsonline.gov.uk/secrets中,因此访问该元素也需要使用XNamespace
XElement MessageBody = xDoc.Element(ns + "Receipts");

作为使用命名空间的替代方案,请注意可以使用“命名空间不可知”的 XPath,使用 local-name()namespace-uri(),例如:
/*[local-name()='SomeElement' and namespace-uri()='somexmlns']

如果省略 namespace-uri 谓词:

/*[local-name()='SomeElement']

可以匹配 ns1:SomeElementns2:SomeElement 等等。在我看来,尽可能使用 XNamespace 总是更好的选择,而无命名空间 xpath 的使用场景非常有限,例如解析未知模式文档中的特定元素(例如在服务总线中),或者最佳努力解析文档,其中命名空间可能会发生更改(例如为了未来的兼容性,xmlns 更改以匹配文档模式的新版本)


1

理论上来说,文档的含义不会受用户命名空间前缀的选择所影响。只要数据在http://www.secretsonline.gov.uk/secrets 命名空间中,作者选择使用前缀"s"、"secrets"、"_x.cafe.babe"或"null"前缀(即使其成为默认命名空间),都无关紧要。你的应用程序不应该关心这些,只有URI才是重要的。这就是为什么你的应用程序必须指定URI。


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