黑暗執行緒

 黑暗執行緒搬新家囉!! http://www.darkthread.net

8/04/2006

XML Attribute的特殊字元處理DIY

我有段程式為了貪圖效能,沒用XmlDocument,而用StringBuilder自己組XML:
sb.AppendFormat("<Event Log=\"{0}\" Message=\"{1}\" />\n",
                    logName,System.Web.HttpUtility.HtmlEncode(e.Message));
結果,今天突然程式發生Error,才發現這段程式乍看OK,嚴謹性卻大有問題。原因出在e.Message中可能包含一些HtmlEncode認定合法,但XML不接受的特殊字元(例如: 換行、\t之類的),組出來的XML是不合法的。

於是,我寫了以下的Code做測試(用了一個ASCII 01(笑臉)跟\n(換行)當成非法)
        static void Lab0802()
        {
            XmlDocument xd = new XmlDocument();
            xd.LoadXml("<ROOT></ROOT>");
            XmlElement xe = xd.CreateElement("X");
            XmlAttribute xa = xd.CreateAttribute("N");
            xa.Value = "<ab>\x1\n</ab>";
            xe.Attributes.Append(xa);
            xd.DocumentElement.AppendChild(xe);
            Console.WriteLine(xd.OuterXml);
            Console.WriteLine(System.Web.HttpUtility.HtmlAttributeEncode(xa.Value));
        }

使用XML DOM的結果,合法的XML應為<ROOT><X N="&lt;ab&gt;&#x1;&#xA;&lt;/ab&gt;" /></ROOT>,而使用HtmlEncode的結果,\n與\x1都沒被置換。當Attribute中出現這些非法字元,在XmlDocument.LoadXml時,就會發生Error!

找了半天,沒找到現成的函數可以處理這個問題(有個XmlConvert.EncodeName()可處理Attribute名稱的特殊字元(例如: 中文),但其規則與Attribute Value的Encode不同,所以無法借用),只好自己DIY寫了這個函數,有類似需求的人可以引用,發現邏輯有錯的話請通知我修改。
        //當字串中可能包含特別的ASCII碼時,做額外的轉換
        public static string XmlAttributeEncode(string raw)
        {
            string s = System.Web.HttpUtility.HtmlEncode(raw);
            StringBuilder sb = new StringBuilder();
            for (int i = 0; i < s.Length; i++)
            {
                char c = s[i];
                //要處理的範圍
                if ((c>=0 && c < 32) || (c > 127 && c<=255))
                    sb.AppendFormat("&#x{0:x};", (byte) c);
                else
                    sb.Append(c);
            }
            return sb.ToString();
        }
 

0 Comments:

Post a Comment

<< Home