首頁
編程語言
C語言|JAVA編程
Python編程
網頁編程
ASP編程|PHP編程
JSP編程
數據庫
MYSQL數據庫|SqlServer數據庫
Oracle數據庫|DB2數據庫
您现在的位置: 程式碼之家 >> 編程語言 >  >> .NET 網頁程式設計 >> 關於.NET

Code4Fun:XML 模板替換實現靈活物件序列化——突破 XmlSerializer 限制的全新方案

     編輯:關於.NET

開發 LINQ2Douban 專案時,發現 XmlSerializer 在處理 Douban API 要求的 XML Entry 格式時遭遇四大痛點:

  1. 不支援泛型集合序列化(IList、IDictionary)
  2. 無法產生部分動態屬性(如 <category term="...#%Category%"> 中僅尾部變動)
  3. 同一實體類別需支援多種序列化格式(新增 vs 更新)
  4. API 格式變更導致程式碼頻繁修改

解決方案:XML 模板 + 反射 = 完全分離結構與資料。模板中用 %% 標記替換點,執行時透過反射取值替換,實現極致彈性。

核心需求與設計目標

需求XmlSerializerXML 模板替換
泛型集合序列化❌ 不支援✅ 支援 IEnumerable 所有實作
靈活層級替換❌ 僅巢狀✅ 任意層級、跨作用域
多格式支援❌ 需修改類別/屬性✅ 同物件套用不同模板
格式變更維護❌ 改代碼重編譯✅ 僅改模板檔案

進階模板語法規格

<channel>
  <title>%Title%</title>
  <link>%Link%</link>
  <category domain="%Category.Domain%">%Category.Name%</category>  <!-- 子物件屬性存取 -->
  <noReplacement>不需要替換</noReplacement>                     <!-- 忽略標記 -->
  <skipHours>
    <hour>%SkipHours%</hour>                                      <!-- 集合展開 -->
  </skipHours>
  <as:scope xmlns:as="https://xml.allsharing.com/" name="Items" type="AllSharing.Xml.Rss.RssItem">
    <item>                                                          <!-- Scope 定義:針對 Items 集合每個元素產生 -->
      <title>%Title%</title>
      <link>%Link%</link>
      <description>%Description%</description>
      <channelCategory>%./Category.Name%</channelCategory>       <!-- ../ 存取父 Scope 屬性 -->
    </item>
  </as:scope>
</channel>

語法關鍵字完整定義

  • %Property%:當前作用域物件屬性
  • %Parent.Child%:巢狀物件屬性鏈
  • %Collection%:IEnumerable 集合自動展開重複節點
  • <as:scope name="Prop" type="Type">:定義新作用域,針對集合屬性逐項產生子節點
  • %./Prop%:存取父作用域屬性(類似相對路徑 ../)
  • <noReplacement>:標記純靜態內容,引擎跳過處理

實體類別定義

public class RssChannel
{
    public string Title { get; set; }
    public string Link { get; set; }
    public RssCategory Category { get; set; }
    public IList<int> SkipHours { get; set; }
    public IList<RssItem> Items { get; set; }
}

public class RssItem
{
    public string Title { get; set; }
    public string Link { get; set; }
    public string Description { get; set; }
}

public class RssCategory
{
    public string Domain { get; set; }
    public string Name { get; set; }
}

核心引擎實作架構

階段一:模板編譯 → Scope 樹建構

// 解析 XML 模板,建構 Scope 樹結構
var scope = XmlTemplateScope.Compile(xmlPath, typeof(RssChannel));

遍歷 XML 節點,識別三類元素:含 %% 的屬性/元素、Scope 節點、忽略節點。建構樹狀結構對應模板巢狀關係。

階段二:資料繫結 → XML 生成


// 載入模板 XDocument,根據 Scope 樹進行替換
var template = new XmlTemplate(xmlPath, scope);
string xml = template.Translate(channelObject);  // 執行替換產出最終 XML
  • 使用 LINQ to XML (XDocument) 操作,比 XmlDocument 簡潔高效
  • 遞迴處理 Scope 樹:屬性值替換、元素值替換、集合節點展開
  • XmlTemplate 為執行緒安全,可快取重用避免重複編譯

實際執行結果展示

var channel = new RssChannel {
    Title = "this is channel title",
    Link = "https://chwkai.cnblogs.com/",
    Category = new RssCategory { Domain = "https://chwkai.cnblogs.com/", Name = "this is channel category" },
    SkipHours = new List<int> { 1, 2, 3 },
    Items = new List<RssItem> {
        new RssItem { Title = "Item1", Link = "Link1", Description = "Des1" },
        new RssItem { Title = "Item2", Link = "Link2", Description = "Des2" },
        new RssItem { Title = "Item3", Link = "Link3", Description = "Des3" }
    }
};

var path = Path.Combine(AppDomain.CurrentDomain.BaseDirectory, "rss.xml");
var template = new XmlTemplate(path, XmlTemplateScope.Compile(path, typeof(RssChannel)));
Console.WriteLine(template.Translate(channel));

輸出 XML

<channel>
  <title>this is channel title</title>
  <link>https://chwkai.cnblogs.com/</link>
  <category domain="https://chwkai.cnblogs.com/">this is channel category</category>
  <noReplacement>不需要替換</noReplacement>
  <skipHours>
    <hour>1</hour><hour>2</hour><hour>3</hour>
  </skipHours>
  <item>
    <title>Item1</title><link>Link1</link><description>Des1</description>
    <channelCategory>this is channel category</channelCategory>
  </item>
  <item>...</item>
  <item>...</item>
</channel>

應用場景擴展

  • RSS/Atom Feed 產生器:模板化輸出,支援多種規範格式
  • Web API Client 開發:請求/回應 XML 模板化,適應 API 版本演進
  • HTML 報表/郵件模板:同樣原理生成 HTML,分離版面與資料
  • 設定檔/程式碼產生器:任何結構化文本輸出場景

此方案將序列化邏輯外部化為聲明式模板,實現結構與資料完全解耦,是處理複雜、多變 XML 格式的終極利器。

  1. 上一篇文章:
  2. 下一篇文章:
Copyright © 程式碼之家 All Rights Reserved