【问题标题】:XML Document SelectSingleNode returns nullXML 文档 SelectSingleNode 返回 null
【发布时间】:2013-06-18 05:42:06
【问题描述】:

我正在尝试从流阅读器读取 XML,并且还获得了响应 XML。但是当我尝试读取它的节点时,它总是返回 null。

var request = (HttpWebRequest) WebRequest.Create(address);
var response = (HttpWebResponse) request.GetResponse();
var stream = response.GetResponseStream();

if(stream != null)
{
   var xmlReader = new XmlTextReader(stream);
   var xmlDocument = new XmlDocument();
   xmlDocument.Load(xmlReader);
   var node = xmlDocument.SelectSingleNode("RateQuote");
}

XML 文档

<RateQuoteResponse xmlns="http://ratequote.usfnet.usfc.com/v2/x1">
  <STATUS>
   <CODE>0</CODE>
   <VIEW>SECURED</VIEW>
   <VERSION>...</VERSION>
  </STATUS>
 <RateQuote>
   <ORIGIN>
     <NAME>KNOXVILLE</NAME>
     <CARRIER>USF Holland, Inc</CARRIER>
     <ADDRESS>5409 N NATIONAL DR</ADDRESS>
     <CITY>KNOXVILLE</CITY>
     <STATE>TN</STATE>
     <ZIP>37914</ZIP>
     <PHONE>8664655263</PHONE>
     <PHONE_TOLLFREE>8006545963</PHONE_TOLLFREE>
     <FAX>8656379999</FAX>
  </ORIGIN>
  <DESTINATION>
     <NAME>KNOXVILLE</NAME>
     <CARRIER>USF Holland, Inc</CARRIER>
     <ADDRESS>5409 N NATIONAL DR</ADDRESS>
     <CITY>KNOXVILLE</CITY>
     <STATE>TN</STATE>
     <ZIP>37914</ZIP>
     <PHONE>8664655263</PHONE>
     <PHONE_TOLLFREE>8006545963</PHONE_TOLLFREE>
     <FAX>8656379999</FAX>
  </DESTINATION>
     <ORIGIN_ZIP>37914</ORIGIN_ZIP>
     <DESTINATION_ZIP>37909</DESTINATION_ZIP>
     <TOTAL_COST>99.24</TOTAL_COST>
     <SERVICEDAYS>1</SERVICEDAYS>
     <INDUSTRYDAYS>1.6</INDUSTRYDAYS>
     <CLASSWEIGHT>
        <CLASS>55</CLASS>
        <ASCLASS>50</ASCLASS>
        <WEIGHT>100</WEIGHT>
        <CHARGES>0.0</CHARGES>
     </CLASSWEIGHT>
</RateQuote>
</RateQuoteResponse>

【问题讨论】:

    标签: c# xml


    【解决方案1】:

    XML 文档使用默认命名空间“http://ratequote.usfnet.usfc.com/v2/x1”。您需要更改 SelectSingleNode 调用以使用此命名空间。

    您需要设置一个 namspace 管理器,然后将其提供给SelectSingleNode

    var nsmgr = new XmlNamespaceManager(doc.NameTable);
    nsmgr.AddNamespace("rate", "http://ratequote.usfnet.usfc.com/v2/x1");
    var node = xmlDocument.SelectSingleNode("//rate:RateQuote", nsmgr);
    

    编辑 RateQuoteResponse 元素有一个默认命名空间xmlns="..."。这意味着所有元素也都使用这个命名空间,除非被特别覆盖。

    【讨论】:

    • @SSS:你又遇到了同样的问题——TOTAL_COST 元素也在那个命名空间中。 (我正在编辑我的答案以提及这一点。)
    • 谢谢。有时我想知道开发这些 API 的人是否真的尝试过使用它们!
    • 或者......忘记所有这些糟糕的命名空间并改用 XPath :) xmlDocument.SelectSingleNode(String.Format("//*[local-name()='{0}']", nodeName));
    • 这就是 XML 正在消亡而 JSON 正在接管的原因。解析 XML 一直是一项艰巨的任务,而且不值得付出努力......
    • 这让我每次都感到兴奋。为什么微软默认的 XML API 这么容易被误用,得到 NULL 结果却没有抛出异常或解释?
    【解决方案2】:

    您可以在读取文件时删除命名空间,只需禁用 XmlTextReader 上的命名空间:

    var request = (HttpWebRequest) WebRequest.Create(address);
    var response = (HttpWebResponse) request.GetResponse();
    var stream = response.GetResponseStream();
    
    if(stream != null)
    {
       var xmlReader = new XmlTextReader(stream);
       xmlReader.Namespaces = false;
       var xmlDocument = new XmlDocument();
       xmlDocument.Load(xmlReader);
       var node = xmlDocument.SelectSingleNode("RateQuote");
    }
    

    之后,在 XML 元素上使用 XPath / LINQ 时,您不必关心命名空间。

    【讨论】:

    • 噗!非常感谢!我花了 3 个小时研究各种不同的解决方案,终于明白命名空间正在破坏整个文档的阅读......
    【解决方案3】:

    问题是您要的是没有命名空间的 RateQuote 元素 - 而 RateQuote 元素 实际上 位于 URI http://ratequote.usfnet.usfc.com/v2/x1 的命名空间中。

    您可以或者使用 XmlNamespaceManager 来处理 XPath 中的命名空间,或者使用具有非常简单的命名空间处理的 LINQ to XML:

    var document = XDocument.Load(stream);
    XNamespace ns = "http://ratequote.usfnet.usfc.com/v2/x1";
    XElement rateQuote = document.Root.Element(ns + "RateQuote");
    

    如果可能的话,我个人会使用 LINQ to XML - 我发现它比XmlDocument 使用起来更愉快。当然,如果您愿意,您仍然可以使用 XPath,但我个人更喜欢使用查询方法。

    编辑:注意命名空间默认也适用于子元素。因此,要找到您需要的 TOTAL_COST 元素:

    XElement cost = document.Root
                            .Element(ns + "RateQuote")
                            .Element(ns + "TOTAL_COST");
    

    【讨论】:

    • 谢谢,您可以发布LINQ 代码示例以选择RateQuote 节点吗?
    • @SSS:这是我发布的代码 - rateQuote 变量指的是&lt;RateQuote&gt; 元素。
    • 谢谢,xml 文档无法加载,它在var document = XDocument.Load(stream); 行中抛出No root element found 错误
    • @SSS:这表明你已经消费了这个流。您是否尝试在将其加载到 XmlDocument 之后执行此操作?
    • 我单独添加的代码会出现该错误。我不确定你在问什么对不起
    【解决方案4】:

    您可能希望在 XmlTextReader 中将 Namespaces 设置为 false

    所以,在你的代码中,改变:

    var xmlReader = new XmlTextReader(stream);
    

    var xmlReader = new XmlTextReader(stream) { Namespaces = false };
    

    通过此更改,您应该能够使用 SelectSingleNode 获取所需的节点,而无需使用命名空间。

    【讨论】:

      【解决方案5】:

      你也应该能够做到:

      ...
      var node = xmlDocument["RateQuote"];
      ...
      

      VB 的语法是:

      ...
      Dim node as XmlNode = xmlDocument("RateQuote")
      ...
      

      【讨论】:

        猜你喜欢
        • 2020-10-05
        • 1970-01-01
        • 1970-01-01
        • 2023-03-07
        • 1970-01-01
        • 1970-01-01
        • 2011-05-09
        • 2010-11-08
        相关资源
        最近更新 更多