2011-09-21 122 views
8

在回答this question時,我遇到了一個我不明白的情況。該OP試圖從以下位置加載XML:http://www.google.com/ig/api?weather=12414&hl=itXmlDocument.Load失敗,LoadXml工作:

顯而易見的解決方案是:

string m_strFilePath = "http://www.google.com/ig/api?weather=12414&hl=it"; 
XmlDocument myXmlDocument = new XmlDocument(); 
myXmlDocument.Load(m_strFilePath); //Load NOT LoadXml 

但是這個失敗

XmlException:在給定的編碼字符無效。第1行,位置499.

它似乎在的à窒息。

OTOH,以下工作正常:

var m_strFilePath = "http://www.google.com/ig/api?weather=12414&hl=it"; 
string xmlStr; 
using(var wc = new WebClient()) 
{ 
    xmlStr = wc.DownloadString(m_strFilePath); 
} 
var xmlDoc = new XmlDocument(); 
xmlDoc.LoadXml(xmlStr); 

我被這個困惑。任何人都可以解釋爲什麼前者失敗,但後者工作正常嗎?

值得注意的是,文檔的xml聲明省略了編碼。

+0

WebClient htmlencodes有可能嗎? – Nicolai

回答

12

WebClient使用在HTTP響應的報頭中的編碼信息,以確定正確的編碼(在這是基於ASCII這種情況下ISO-8859-1,即8每個字符的比特)

它看起來像XmlDocument.Load不使用這個信息和編碼也是從xml聲明中丟失的,它必須在編碼時猜測並得到錯誤。一些挖掘導致我相信它選擇UTF-8。

如果我們想獲得真正的技術,它拋出的字符是「à」,即ISO-8859-1編碼中的0xE0,但這不是UTF-8中的有效字符 - 具體來說,這個人物是:

11100000 

如果你有一個周圍挖在UTF-8 Wikipedia article我們可以看到,這表明一個代碼點(即字符)組成的共3個字節採取以下格式:

Byte 1  Byte 2  Byte 3 
----------- ----------- ----------- 
1110xxxx 10xxxxxx 10xxxxxx 

但是,如果我們有一個回顧文檔後面的兩個字符是「:」,它是ISO-8859-1中的0x3A和0x20。這意味着我們實際上最終得到的是:

Byte 1  Byte 2  Byte 3 
----------- ----------- ----------- 
11100000 00111010 00100000 

無論是順序的第二或第三個字節具有10作爲兩個最顯著位(這將表明繼續),所以這種性格使得沒有任何意義UTF-8。

+0

現在打開Reflector ... – spender

+0

查看代碼,看起來Load實例化了一個'XmlTextReader',但沒有嘗試設置編碼。 – spender

+0

@spender是的,我看了一下ILSpy裏面的內容,但很難看清究竟發生了什麼 - 有趣的問題,但我喜歡回答這個問題!:-) – Justin

2

Umidità字符串作爲節點innertext必須在<! [CDATA [Umidità]]>這不會在XmlDocument.Load中給出任何錯誤。

+0

這個問題不是關於如何修復XML,而是爲什麼我上面的問題中概述的兩種方法的行爲不同。 – spender

+1

事實上,CDATA標記向分析器指示字符數據,以便XML構造(如「<」)不需要轉義,但在這種情況下,它的編碼問題 - 使用CDATA標記在這裏沒有任何區別。 – Justin