XML Document SelectSingleNode返回null

20 c# xml

我试图从流阅读器读取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");
}
Run Code Online (Sandbox Code Playgroud)

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>
Run Code Online (Sandbox Code Playgroud)

Ric*_*der 39

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);
Run Code Online (Sandbox Code Playgroud)

编辑RateQuoteResponse元素有一个默认的命名空间xmlns="...".这意味着除非特别重写,否则所有元素也会使用此命名空间.

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

Flo*_* D. 11

您可以在读取文件时删除命名空间,只需禁用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");
}
Run Code Online (Sandbox Code Playgroud)

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


Jon*_*eet 9

问题是你要求的是一个RateQuote没有命名空间的RateQuote元素- 而该元素实际上是在带有URI的命名空间中http://ratequote.usfnet.usfc.com/v2/x1.

您可以任意使用XmlNamespaceManager,解决您的XPath内的命名空间,或使用LINQ到XML具有非常简单的命名空间的处理:

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

就个人而言,如果可能的话,我会使用LINQ to XML - 我发现使用它比使用它更愉快XmlDocument.如果你想要的话,你仍然可以使用XPath,但我个人更喜欢使用查询方法.

编辑:请注意,名称空间默认也适用于子元素.所以要找到TOTAL_COST你需要的元素:

XElement cost = document.Root
                        .Element(ns + "RateQuote")
                        .Element(ns + "TOTAL_COST");
Run Code Online (Sandbox Code Playgroud)


Fil*_*age 6

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

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

var xmlReader = new XmlTextReader(stream);
Run Code Online (Sandbox Code Playgroud)

var xmlReader = new XmlTextReader(stream) { Namespaces = false };
Run Code Online (Sandbox Code Playgroud)

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