CodeGym /課程 /C# SELF /使用 XmlSerializer 做 ...

使用 XmlSerializer 做 XML 序列化

C# SELF
等級 44 , 課堂 2
開放

1. 介紹

XML 是 eXtensible Markup Language 的縮寫。想像一個非常嚴謹又愛說話的 JSON,不停跟你說「我很有結構,相信我!」。XML 是一種以標籤包裹資料的純文字格式:

<Player>
  <Name>Aragorn</Name>
  <Health>100</Health>
</Player>

為什麼現在還要把物件序列化成 XML?

  • XML 在大型系統整合(常見於「legacy」系統)裡仍被廣泛使用,特別是需要結構與基於嚴格 schema(XSD)的驗證時。
  • 在企業設定上也常見 XML(例如舊版 .NET 的 App.configWeb.config)。
  • 當你需要資料的「自我描述性」時,XML 很適合這種場景。

有趣的事:XML 最初設計時就是要盡可能地「可擴充」和可驗證;名字就是從這來的。它可以用 schema(例如 XSD)做驗證,這是 JSON 預設沒辦法做到的。

XmlSerializer:主角

在 .NET 中負責把物件序列化成 XML 的類別是 System.Xml.Serialization.XmlSerializer

  • 它會把公開的(public)屬性和欄位轉成 XML 元素,反之亦然:由 XML 還原物件。
  • 只對公開的型別與成員有效。
  • 不會序列化 private 的欄位與屬性 — 只有公開的會被處理。
  • 序列化的類別需要有一個無參數的建構子(constructor)。

注意:如果你的類別不滿足這些條件,XmlSerializer 就無法工作,會在序列化或反序列化時丟出例外。

2. 簡單範例 — 將物件序列化成 XML

我們來看怎麼把我們常用的 Player 類序列化成 XML。

步驟 1. 定義類別

public class Player
{
    public string Name { get; set; }
    public int Health { get; set; }
    public bool IsAlive { get; set; }

    // 重要:需要一個無參數的公共建構子(constructor)!
    public Player() { }

    // 可選:方便起見
    public Player(string name, int health, bool isAlive)
    {
        Name = name;
        Health = health;
        IsAlive = isAlive;
    }
}

步驟 2. 序列化到檔案

using System.Xml.Serialization;

Player aragorn = new Player("Aragorn", 100, true);

// 1. 為 Player 型別建立 XmlSerializer
XmlSerializer serializer = new XmlSerializer(typeof(Player));

// 2. 開檔寫入(檔案不存在會自動建立)
using FileStream fs = new FileStream("player.xml", FileMode.Create);

// 3. 將物件序列化成 XML
serializer.Serialize(fs, aragorn);

結果 (player.xml):

<?xml version="1.0"?>
<Player xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" 
        xmlns:xsd="http://www.w3.org/2001/XMLSchema">
  <Name>Aragorn</Name>
  <Health>100</Health>
  <IsAlive>true</IsAlive>
</Player>

最簡流程視覺示意


記憶體中的物件  --->  XmlSerializer.Serialize()  --->  磁碟上的 XML 檔案

3. 反序列化 — 從 XML 把物件「喚回」

當你要讀回先前序列化的物件,流程是反過來:

using FileStream fs = new FileStream("player.xml", FileMode.Open);
XmlSerializer serializer = new XmlSerializer(typeof(Player));
Player player = (Player)serializer.Deserialize(fs);

Console.WriteLine($"姓名: {player.Name}, 生命值: {player.Health}, 存活: {player.IsAlive}");

結果程式會輸出: 姓名: Aragorn, 生命值: 100, 存活: True

4. 序列化成字串 — 不只寫檔案

序列化成字串

有時你不想把東西寫成檔案,可能要把 XML 當字串傳網路或顯示在畫面上。

using System.IO;
using System.Xml.Serialization;

Player player = new Player("Frodo", 42, true);

XmlSerializer serializer = new XmlSerializer(typeof(Player));
StringWriter stringWriter = new StringWriter();
serializer.Serialize(stringWriter, player);

string xmlString = stringWriter.ToString();
Console.WriteLine(xmlString); // 整段 XML 字串會輸出在螢幕上!

從字串反序列化

同樣地,你也可以從字串而不是檔案反序列化物件:

string xml = "<Player Name=\"Frodo\"><HP>42</HP></Player>";
XmlSerializer serializer = new XmlSerializer(typeof(Player));

using StringReader stringReader = new StringReader(xml);
Player frodo = (Player)serializer.Deserialize(stringReader);
Console.WriteLine(frodo.Name); // Frodo

5. XML 客製化:用屬性控制結構

如果預設行為不合你胃口,像是 XML 太冗長或標籤名稱不對,這時可以靠幾個「魔法」屬性直接告訴序列化器該怎麼處理類別成員。

常用的:

  • [XmlElement]
    — 指定元素名稱。
  • [XmlAttribute]
    — 把欄位當成 XML attribute(屬性),而不是 element(元素)。
  • [XmlIgnore]
    — 從序列化中排除該屬性。
  • [XmlArray]
    [XmlArrayItem]
    — 控制集合的包裝(wrapper)和項目名稱。

使用範例:

public class Player
{
    [XmlAttribute]
    public string Name { get; set; }
    [XmlElement("HP")]
    public int Health { get; set; }
    [XmlIgnore]
    public bool IsTempSessionPlayer { get; set; }
}

輸出 XML:

<Player Name="Aragorn">
  <HP>100</HP>
</Player>

序列化主要屬性表

屬性 影響 範例
[XmlAttribute]
把屬性變成 XML attribute
<Player Name="Aragorn">...</Player>
[XmlElement]
改變標籤名稱
<HP>100</HP>
代替
<Health>100</Health>
[XmlIgnore]
完全從序列化中排除該屬性
[XmlArray]
改變集合「包裹」名稱
<Heroes> ... </Heroes>
[XmlArrayItem]
改變集合中每個項目的名稱
<Hero>...</Hero>

集合的進階序列化範例:

public class GameWorld
{
    [XmlArray("Heroes")]
    [XmlArrayItem("Hero")]
    public List<Player> Players { get; set; } = new List<Player>();
}

XML:

<GameWorld>
  <Heroes>
    <Hero Name="Legolas">
      <HP>90</HP>
    </Hero>
    <!-- ... -->
  </Heroes>
</GameWorld>

關於 XML 的進階客製化,我們會在後面的講義再講! :P

留言
TO VIEW ALL COMMENTS OR TO MAKE A COMMENT,
GO TO FULL VERSION