2013-06-18 41 views
13

Tôi đang cố gắng đọc XML từ trình đọc luồng và cũng nhận được phản hồi XML. Nhưng khi tôi cố gắng đọc các nút của nó, nó luôn luôn trả về null.Tài liệu XML SelectSingleNode trả về 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"); 
} 

tài liệu 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> 

Trả lời

26

Các tài liệu XML sử dụng không gian tên mặc định "http://ratequote.usfnet.usfc.com/v2/x1". Bạn cần thay đổi cuộc gọi SelectSingleNode để sử dụng không gian tên này.

Bạn cần thiết lập trình quản lý không gian tên và sau đó cung cấp cho SelectSingleNode.

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

EDIT Các RateQuoteResponse phần tử có một không gian tên mặc định xmlns="...". Điều này có nghĩa là tất cả các phần tử đều sử dụng không gian tên này, trừ khi được ghi đè cụ thể.

+1

Cảm ơn ví dụ ... –

+0

'var node = xmlDocument.SelectSingleNode (" // rate: RateQuote/TOTAL_COST ", nsmgr);' Tại sao tính năng này không hoạt động? Nó lại ném 'null' –

+2

@SSS: Bạn lại gặp vấn đề tương tự - phần tử' TOTAL_COST' cũng nằm trong không gian tên đó. (Tôi đang chỉnh sửa câu trả lời của mình để đề cập đến điều này.) –

6

Vấn đề là bạn đang yêu cầu cho một yếu tố RateQuote mà không có một không gian tên - trong khi các yếu tố RateQuotethực trong namespace URI http://ratequote.usfnet.usfc.com/v2/x1.

Bạn có thể hoặc sử dụng một XmlNamespaceManager để giải quyết các namespace trong XPath của bạn, hoặc sử dụng LINQ to XML trong đó có xử lý không gian tên rất đơn giản:

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

Cá nhân tôi sẽ sử dụng LINQ to XML nếu bạn có thể - Tôi thấy dễ chịu hơn khi sử dụng hơn XmlDocument. Bạn vẫn có thể sử dụng XPath nếu bạn muốn tất nhiên, nhưng cá nhân tôi thích sử dụng các phương thức truy vấn.

EDIT: Lưu ý rằng không gian tên mặc định cũng áp dụng cho các phần tử con. Vì vậy, để tìm ra yếu tố TOTAL_COST bạn cần:

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

Cảm ơn, bạn có thể gửi ví dụ mã' LINQ' để chọn nút 'RateQuote'? –

+0

@SSS: Đó là mã mà tôi * đã đăng - biến 'rateQuote' đề cập đến phần tử' '. –

+0

ok thankyou .... –

5

Bạn có thể loại bỏ các namespace trong khi đọc file, chỉ cần vô hiệu hóa các không gian tên trên 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"); 
} 

Sau đó bạn không có để quan tâm đến không gian tên trong khi sử dụng XPath/LINQ trên các phần tử XML của bạn.

+0

pfff! Cảm ơn nhiều! Tôi đã dành 3 giờ trên các giải pháp khác nhau để cuối cùng hiểu rằng việc đặt tên không gian đang làm hỏng toàn bộ việc đọc tài liệu ... – Cowwando

1

Bạn cũng sẽ có thể làm:

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

Cú pháp VB cho điều đó là:

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

Thay đổi:

var xmlReader = new XmlTextReader(stream); 
var xmlDocument = new XmlDocument(); 
xmlDocument.Load(xmlReader); 

để

var xmlReader = new XmlTextReader(stream) { Namespaces = false }; 
var xmlDocument = new XmlDocument(); 
xmlDocument.Load(xmlReader); 

Nhưng ...bạn cũng có thể cải thiện mã một chút, và sử dụng một cái gì đó như thế này:

var xmlDocument = new XmlDocument(); 
xmlDocument.Load(new XmlTextReader(stream) { Namespaces = false }); 

Và nếu bạn muốn tải từ một chuỗi dữ liệu XML, bạn có thể sử dụng:

var xmlDocument = new XmlDocument(); 
xmlDocument.Load(new XmlTextReader(new StringReader(data)) { Namespaces = false }); 

Với sự thay đổi này, bạn nên có thể nhận được nút bạn muốn với SelectSingleNode mà không cần phải sử dụng các không gian tên.