8

詭異的 XDocument XML 讀取錯誤

 3 years ago
source link: https://blog.darkthread.net/blog/xml-file-parse-bom-issue/
Go to the source link to view the article. You can view the picture content, updated content and better typesetting reading experience. If the link is broken, please click the button below to view the snapshot at that time.

詭異的 XDocument XML 讀取錯誤

calendar.svg 2021-03-01 09:42 AM comment.svg 0 eye.svg 1,246

被一個 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,而我的程式傻傻地讓它變成字串內容,引發錯誤。

再學到一些實戰經驗。

and has 0 comments

Comments

Be the first to post a comment

Post a comment

Comment
Name Captcha 6 + 4 =

About Joyk


Aggregate valuable and interesting links.
Joyk means Joy of geeK