【问题标题】:Parse XDocument without having to keep specifying the default namespace解析 XDocument 而不必一直指定默认命名空间
【发布时间】:2011-11-15 06:26:44
【问题描述】:

我有一些 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="") 中。
  • 是否可以清除默认命名空间,以免我不得不在每个元素名称中添加“ns+”?

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


【解决方案1】:

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

【讨论】:

  • 在 XDocument 中不是通过定义 xmlns="someNamespace" 定义的默认命名空间。当您编写 XML 的文本版本时,您不必指定默认 ns,因此我不希望必须使用代码来执行此操作。
【解决方案2】:

请注意,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 更改以匹配文档模式的新版本)

【讨论】:

    【解决方案3】:

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

    【讨论】:

      【解决方案4】:

      正如this answer 所建议的,您可以通过从文档的内存副本中删除所有命名空间来做到这一点。我想只有在您知道结果文档中不会出现名称冲突的情况下才应该这样做。

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

      【讨论】:

        【解决方案5】:

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

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

        【讨论】:

        • 您已经将 xml 读取为字符串了吗? XmlDocument 对字符串有 Parse only 方法,您必须做很多工作将字符串转换为 xreader 的流。
        猜你喜欢
        • 1970-01-01
        • 1970-01-01
        • 2022-01-20
        • 2011-02-21
        • 2015-04-13
        • 1970-01-01
        • 2015-12-14
        • 1970-01-01
        相关资源
        最近更新 更多