解析 XDocument,无需继续指定默认命名空间

发布于 2024-12-04 06:37:17 字数 958 浏览 0 评论 0原文

我有一些 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");

I have some XML data (similar to the sample below) and I want to read the values in code.

Why am I forced to specify the default namespace to access each element? I would have expected the default namespace to be used for all elements.

Is there a more logical way to achieve my goal?

Sample 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>

Code to read xml elements I'm after:

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");

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(5

薄情伤 2024-12-11 06:37:17

正如此答案所建议的,您可以通过从文档的内存副本中删除所有命名空间来实现此目的。我想只有当您知道生成的文档中不会出现名称冲突时才应该这样做。

/// <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());
    }
}

As suggested by this answer, you can do this by removing all namespaces from the in-memory copy of the document. I suppose this should only be done if you know you won't have name collisions in the resulting document.

/// <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());
    }
}
弥繁 2024-12-11 06:37:17

您可以使用 XmlTextReader.Namespaces 属性可在读取 XML 文件时禁用命名空间。

string filePath;
XmlTextReader xReader = new XmlTextReader(filePath);
xReader.Namespaces = false;
XDocument xDoc = XDocument.Load(xReader);

You can use XmlTextReader.Namespaces property to disable namespaces while reading XML file.

string filePath;
XmlTextReader xReader = new XmlTextReader(filePath);
xReader.Namespaces = false;
XDocument xDoc = XDocument.Load(xReader);
温暖的光 2024-12-11 06:37:17

这就是 Linq-To-Xml 的工作原理。如果任何元素不在默认命名空间中,则您无法找到任何元素,并且其后代也是如此。摆脱命名空间的最快方法是从初始 XML 中删除指向命名空间的链接。

This is how the Linq-To-Xml works. You can't find any element, if it is not in default namespace, and the same is true about its descendants. The fastest way to get rid from namespace is to remove link to the namespace from your initial XML.

无戏配角 2024-12-11 06:37:17

理论上,文档的含义不受用户选择的命名空间前缀的影响。只要数据位于命名空间 http://www.secretsonline.gov.uk/secrets,作者选择使用前缀“s”、“secrets”、“_x.cafe.babe”还是“null”前缀(即使其成为默认命名空间)并不重要。您的应用程序不应该关心:重要的只是 URI。这就是您的应用程序必须指定 URI 的原因。

The theory is that the meaning of the document is not affected by the user's choice of namespace prefixes. So long as the data is in the namespace http://www.secretsonline.gov.uk/secrets, it doesn't matter whether the author chooses to use the prefix "s", "secrets", "_x.cafe.babe", or the "null" prefix (that is, making it the default namespace). Your application shouldn't care: it's only the URI that matters. That's why your application has to specify the URI.

枕花眠 2024-12-11 06:37:17

请注意,元素 Receipts 也在命名空间 http://www.secretsonline.gov.uk/secrets 中,因此 XNamespace 也将是访问元素所需的:

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

作为使用命名空间的替代方法,请注意,您可以使用 local-name()namespace-uri() 来使用“命名空间不可知”xpath ,例如

/*[local-name()='SomeElement' and namespace-uri()='somexmlns']

如果您省略namespace-uri 谓词:

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

将匹配 ns1:SomeElementns2:SomeElement 等。IMO 我总是更喜欢 XNamespace 在可能的情况下,与命名空间无关的 xpath 的用例非常有限,例如用于解析具有未知模式的文档中的特定元素(例如在服务总线内),或者尽力解析命名空间可以更改的文档(例如未来校对,其中 xmlns 发生更改以匹配新版本的文档架构)

Note that the element Receipts is also in namespace http://www.secretsonline.gov.uk/secrets, so the XNamespace would also be required for the access to the element:

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

As an alternative to using namespaces note that you can use "namespace agnostic" xpath using local-name() and namespace-uri(), e.g.

/*[local-name()='SomeElement' and namespace-uri()='somexmlns']

If you omit the namespace-uri predicate:

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

Would match ns1:SomeElement and ns2:SomeElement etc. IMO I would always prefer XNamespace where possible, and the use-cases for namespace-agnostic xpath are quite limited, e.g. for parsing of specific elements in documents with unknown schemas (e.g. within a service bus), or best-effort parsing of documents where the namespace can change (e.g. future proofing, where the xmlns changes to match a new version of the document schema)

~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文