被一個 XML 讀取問題卡住大半天,寫篇筆記留念。

我有個 Coding4Fun 電子書製作工具,將 XHTML 範本檔案內嵌成資源(Embedded Resource),再用 GetEmbResString() 讀取範本 XML 交給 XDocument.Parse() 轉成 XML 物件操作:

static string GetEmbResString(string name) => 
    Encoding.UTF8.GetString(GetEmbResBytes(name));


static byte[] GetEmbResBytes(string name)
{
    using (var ms = new MemoryStream())
    {
        GetEmbResStream(name).CopyTo(ms);
        return ms.ToArray();
    }
}

static Stream GetEmbResStream(string name) => 
    typeof(EPubMaker).Assembly.GetManifestResourceStream(
        typeof(EPubMaker).FullName.Replace(nameof(EPubMaker), "Templates." + name));
        
//... 讀取 XML 範本轉為 XDocument ...
var template = GetEmbString("template.html");
XDocument.Parse(template);

該 XML 範本在其他地方有用過,內容、格式應該都符合規範。不料,系統噴出 System.Xml.XmlException: 'Data at the root level is invalid. Line 1, position 1.' 錯誤!

有趣的是,我如果換個寫法,改取 Stream 再配合 XDocument.Load 就過關了:

var template = GetEmbResStream("template.html");
XDocument.Load(template);

經過一番研究,我終於搞懂是怎麼一回事了(結論是自己學藝不精、江湖經驗不足),並知道怎麼重現它:

如以上範例,我做了一個超簡單的 XML 檔案,跑 XDocument.Load(XML檔)、XDocument.Parse(File.ReadAllText(XML檔)) 都沒問題;但如果先 File.ReadAllBytes(XML檔) 讀成 byte[] 再 Encoding.UTF8.GetString() 轉字串餵給 XDocument.Parse(),便會重現"在根層次的資料無效。行1,位置1。"錯誤。

聰明的你,想到是什麼原因了嗎?

Yes,UTF8 BOM!

用 BitConverter.ToString(byte[]) 檢視 ReadAllBytes() 讀取的二進位內容,果然在最前方看到 EF BB BF (UTF8 BOM),File.ReadAllText()、XDocument.Load() 這些處理檔案的函式都認得 BOM,而我的程式傻傻地讓它變成字串內容,引發錯誤。

再學到一些實戰經驗。

A case of UTF-8 BOM issue while processing XML with XDocument.Parse().


Comments

# by 阿光

今天遇到用XDocument.Load會出現 要求已經中止: 無法建立 SSL/TLS 的安全通道的問題

# by Jeffrey

to 阿光,是 .NET 3.5/4/4.5 程式嗎?最常見原因是 TLS 1.2 設定,請參考這篇第 4 點 https://blog.darkthread.net/blog/disable-tls-1-0-issues/ 簡單測試方法 - 同樣程式若改用 .NET 4.6+ 不會出錯,即可確認是 TLS 1.2 問題。

# by 阿光

謝謝黑暗大大的回覆。 是.Net 4.7.2版本,嘗試很多方式都不行,唯獨用了RestSharp套件可以。 但是在XDocument.Parse會出現System.Xml.XmlException: 遺漏根元素。

# by Jeffrey

to 阿光,用瀏覽器開一下 XML URL,看看是否憑證無效,若是停用驗證試試 ServicePointManager.ServerCertificateValidationCallback = delegate { return true; }; https://blog.darkthread.net/blog/webclient-ssl-dismatch/

# by cheng

抱歉,有人有遇過XDocument.Load()後發生Unable to connect to the remote server嗎 而且是有時有,有時沒有一直沒法找到原因

Post a comment