[技術探討] XML序列化 (Serialize)與反序列化(Deserialize) – 下篇

XML序列化

Xml序列化和反序列化功能應用已於《 XML序列化(Serialize)與反序列化(Deserialize) – 上篇 》詳細介紹示範過,但是有時候僅知道Xml格式內容的字串,並沒有Xml檔案,在程式開發上也常常需要轉換為物件,以利於程序處理,這時該如何進行轉換? Xml序列化技術應用極廣,最近於公司簡訊的發送SMS、MMS專案,以及新產品NAS (網路儲存伺服器)的應用程式,在開發上皆有使用到這些技術。以下例子為使用Xml字串進行序列化和反序列化的功能示範。

如何序列化取得Xml字串內容

若只想取得序列化物件資料內容,並不想儲存為Xml檔案,序列化時可使用StringWriter方式達到目的,示範程式碼如下例子所示:

  • 序列化取得Xml字串內容

  /// <summary>
        /// 取得類別序列化的XML格式字串
        /// </summary>
        /// <param name="obj"></param>
        /// <returns></returns>
        public static string SerializeToString(object obj)
        {
            string xmlString = string.Empty;
            StringWriter writer = null;
            try
            {
                XmlSerializer xml = new XmlSerializer(obj.GetType());
                writer = new StringWriter();
                xml.Serialize(writer, obj);
                xmlString = writer.ToString();
            }
            catch (Exception ex)
            {
                throw ex;
            }
            finally
            {
                writer.Close();
            }
            return xmlString;
        }
  • 示範用法

  Person p = new Person();
p.Name = "M.K.";
p.Phone = "0950123456";
string xmlString = XmlSerialize.SerializeToString(p);
  • 執行結果 – xmlString內容

<?xml version="1.0" encoding="utf-16"?>
<Person xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:xsd="http://www.w3.org/2001/XMLSchema">
  <Name>M.K.</Name>
  <Phone>0950123456</Phone>
</Person>
  • 想移除Xml Namespaces內容,即上述執行結果的「xmlns:xsi=”http://www.w3.org/2001/XMLSchema-instance” xmlns:xsd=http://www.w3.org/2001/XMLSchema」,可調整SerializeToString方法,於序列化時使用XmlSerializerNamespaces方式達到目的,示範程式碼如下例子所示:

       /// <summary>
        /// 取得類別序列化的XML格式字串
        /// </summary>
        /// <param name="obj"></param>
        /// <returns></returns>
        public static string SerializeToString(object obj)
        {
            string xmlString = string.Empty;
            StringWriter writer = null;
            try
            {
                XmlSerializer xml = new XmlSerializer(obj.GetType());
                writer = new StringWriter();
                XmlSerializerNamespaces namespaces = new XmlSerializerNamespaces();
                namespaces.Add(string.Empty, string.Empty);
                xml.Serialize(writer, obj, namespaces);
            }
            catch (Exception ex)
            {
                throw ex;
            }
            finally
            {
                writer.Close();
            }
            return xmlString;
        }
  • 執行結果 – xmlString內容 (已移除Xml命名空間)

<?xml version="1.0" encoding="utf-16"?>
<Person>
  <Name>M.K.</Name>
  <Phone>0950123456</Phone>
</Person>
  • 使用泛型寫法並移除Xml宣告與Namespaces內容,於序列化時使用XmlWriter 和XmlSerializerNamespaces方式達到目的,示範程式碼如下例子所示:
  • 泛型序列化XML字串

 /// <summary>
        /// 取得類別序列化的XML格式字串,移除XML命名空間。
        /// </summary>
        /// <typeparam name="T"></typeparam>
        /// <param name="value"></param>
        /// <returns></returns>
        public static string SerializeToStringOmitDeclaration<T>(T value)
        {
            if (value == null)
                return null;
            try
            {
                XmlSerializer serializer = new XmlSerializer(typeof(T));

                XmlWriterSettings settings = new XmlWriterSettings();
                settings.OmitXmlDeclaration = true;

                using (StringWriter textWriter = new StringWriter())
                {
                    using (XmlWriter xmlWriter = XmlWriter.Create(textWriter, settings))
                    {
                        XmlSerializerNamespaces namespaces = new XmlSerializerNamespaces();
                        namespaces.Add("", "");
                        serializer.Serialize(xmlWriter, value, namespaces);
                    }
                    return textWriter.ToString();
                }
            }
            catch (Exception ex)
            {
                return null;
            }
        }
  • 示範用法

Person p = new Person();
p.Name = "M.K.";
p.Phone = "0950123456";

string xmlString = XmlSerialize.SerializeToStringOmitDeclaration<Person>(p);
  • 執行結果 – xmlString內容 (已移除Xml宣告與命名空間)

<Person>
  <Name>M.K.</Name>
  <Phone>0950123456</Phone>
</Person>

如何使用Xml字串反序列化(並移除命名空間)

只有Xml字串內容想使用反序列化方式取得物件資料,示範程式碼如下例子所示:

  • 反序列化XML字串

        /// <summary>
        /// 反序列化並移除Namespace資料
        /// </summary>
        /// <typeparam name="T"></typeparam>
        /// <param name="xmlString"> XML字串內容</param>
        /// <returns></returns>
        public static T DeserializeOmitNamespace<T>(string xmlString)
        {
            try
            {
                XmlSerializer xs = new XmlSerializer(typeof(T));
                using (StringReader reader = new StringReader(xmlString))
                {
                    object obj = xs.Deserialize(new OmitNamespaceXmlTextReader(reader));
                        return (T)obj;
                }
            }
            catch (Exception ex)
            {
                return default(T);
            }
        }

        public class OmitNamespaceXmlTextReader : XmlTextReader
        {
            public OmitNamespaceXmlTextReader(TextReader reader) : base(reader) { }
            public override string NamespaceURI
            {
                get { return ""; }
            }
        }
  • XML測試字串內容

<?xml version="1.0" encoding="utf-8"?>
<Person xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:xsd="http://www.w3.org/2001/XMLSchema">
  <Name>M.K.</Name>
  <Phone>0950123456</Phone>
</Person>
  • 示範用法

// xmlString 為XML測試字串內容
string xmlString = "<?xml version=\"1.0\" encoding=\"utf-8\"?><Person xmlns:xsi=\"http://www.w3.org/2001/XMLSchema-instance\" xmlns:xsd=\"http://www.w3.org/2001/XMLSchema\"><Name>M.K.</Name><Phone>0950123456</Phone></Person>";

Person person = XmlSerialize.DeserializeOmitNamespace<Person>(xmlString);

示範例子為寫一個OmitNamespaceXmlTextReader類別去繼承XmlTextReader並覆寫NamespaceURI值為空值,並使用於反序列化以達成移除xml namespaces。

使用MemoryStream將Xml字串反序列化

也可使用MemoryStream寫法反序列化,示範程式碼如下例子所示:

  • MemoryStream反序列化XML字串

        /// <summary>
        /// 反序列化XML檔案內容,並使用MemoryStream 處理
        /// </summary>
        /// <typeparam name="T"></typeparam>
        /// <param name="xmlString"></param>
        /// <returns></returns>
        public static T DeserializeUseMemory<T>(string xmlString)
        {
            try
            {
                using (MemoryStream ms = new MemoryStream(Encoding.UTF8.GetBytes(xmlString)))
                {
                    XmlSerializer xs = new XmlSerializer(typeof(T));
                    object obj = xs.Deserialize(ms);
                    return (T)obj;
                }
            }
            catch (Exception ex)
            {
                return default(T);
            }
        }
  • 示範用法

// xmlString 為XML測試字串內容
string xmlString = "<?xml version=\"1.0\" encoding=\"utf-8\"?><Person xmlns:xsi=\"http://www.w3.org/2001/XMLSchema-instance\" xmlns:xsd=\"http://www.w3.org/2001/XMLSchema\"><Name>M.K.</Name><Phone>0950123456</Phone></Person>";

Person person = XmlSerialize.DeserializeUseMemory<Person>(xmlString);

MSDN參考資料

XmlSerializerNamespaces 類別

XmlTextReader.NamespaceURI 屬性

 

stackoverflow參考資料

Serialize an object to string

Using StringWriter for XML Serialization

Can I make XmlSerializer ignore the namespace on deserialization?

 

相關資料

[C#.NET] 序列化到MemoryStream

 


發佈留言

這個網站採用 Akismet 服務減少垃圾留言。進一步了解 Akismet 如何處理網站訪客的留言資料