都 2021 年了,竟然有人搞大資料時忽略 JSON 而去研究用 C# 把 XML 轉換為 XML 的技術

Soar、毅發表於2021-05-24

在大資料專案開發過程中,ETL(Extract-Transform-Load)是必不可少。即便目前 JSON 非常流行,開發人員也有必定會有對遠古系統的挑戰,而 XML 格式的資料來源作為經典存在渾身上下散發著濃濃 old money 的味道。

因為有 Newtonsoft.Json 這樣優秀的 JSON 框架存在,開發人員可以很容易的對 JSON 格式的字串反序列化。但是 XML 格式的資料就沒有這麼方便了:雖然 .NET 中內建了對 XML 序列化和反序列化的支援,但遇到需要對接外部資料時就不是很方便了。

使用 XmlReader 讀取資料

從 XML 中提取目標資料最高效,也最麻煩的方式是直接使用 XmlReader :

<employee xmlns="urn:empl-hire">
<ID>12365</ID>
<hire-date>2003-01-08</hire-date>
<title>Accountant</title>
</employee>

使用以下程式碼對上述 hireDate.xml 檔案讀取:

using (XmlReader reader = XmlReader.Create("hireDate.xml")) {
 
// Move to the hire-date element.
reader.MoveToContent();
reader.ReadToDescendant("hire-date");
 
// Return the hire-date as a DateTime object.
DateTime hireDate = reader.ReadElementContentAsDateTime();
Console.WriteLine("Six Month Review Date: {0}", hireDate.AddMonths(6));
}

輸出:

Six Month Review Date: 7/8/2003 12:00:00 AM

使用 XDocument 讀取資料

在 .NET Framework 3.5 釋出後的時間裡,開發人員可以使用 XDocument 來生成和解析 XML 文件,這要比 XmlReader 方便的多:

string str =
@"<?xml version=""1.0""?>
<!-- comment at the root level -->
<Root>
<Child>Content</Child>
</Root>";
XDocument doc = XDocument.Parse(str);
Console.WriteLine(doc.XPathSelectElement("//Child"));

輸出:

<Child>Content</Child>

但硬編碼的 XPath 並不方便除錯,而且需要時刻關注空引用的問題。在 XML 格式複雜、專案工程比較大時使用起來也不方便。

一種把 XML 轉換為 XML 的技術: XSLT

在電腦科學中,可擴充套件樣式錶轉換語言(英語:Extensible Stylesheet Language Transformations,縮寫XSLT)是一種樣式轉換標記語言,可以將XML資料檔轉換為另外的XML或其它格式,如HTML網頁,純文字。XSLT最末的T字母表示英語中的“轉換”(transformation)。

簡單來說,開發人員可以藉助 XSLT 技術編寫一個 XML 檔案,並使用該檔案將一種 XML 格式轉換為另一種 XML 。即:在對接複雜格式 XML 資料來源時,開發人員可以編寫一個字尾為 .xsl 的檔案,並使用該檔案將資料來源格式轉換為自己需要的格式(比如可以適配 XML 反序列化的格式)。

從一個簡單的 XML 檔案開始:

<?xml version="1.0" encoding="ISO-8859-1"?>
<catalog>
<cd>
<title>Empire Burlesque</title>
<artist>Bob Dylan</artist>
<country>USA</country>
<company>Columbia</company>
<price>10.90</price>
<year>1985</year>
</cd>
.
.
.
</catalog>

如果直接在瀏覽器開啟這個檔案:

假設我們只關心所有的 title 資訊,可以使用下面的 cdcatalog.xsl 檔案,該檔案可以將 cdcatalog.xml 轉為 XmlSerializer 所需要的格式:

<?xml version="1.0" encoding="ISO-8859-1"?>
<xsl:stylesheet version="1.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform">
<xsl:output method="xml" indent="yes"/>
<xsl:template match="/">
<ArrayOfString xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:xsd="http://www.w3.org/2001/XMLSchema">
<xsl:for-each select="catalog/cd">
<string>
<xsl:value-of select="title"/>
</string>
</xsl:for-each>
</ArrayOfString>
</xsl:template>
</xsl:stylesheet>

為了可以在瀏覽器中直接觀察到轉換效果,可以選擇把 XSL 樣式錶連結到 XML 文件:向 XML 文件(”cdcatalog.xml”)新增 XSL 樣式表引用即可。

<?xml version="1.0" encoding="ISO-8859-1"?>
<?xml-stylesheet type="text/xsl" href="cdcatalog.xsl"?>
<catalog>
<cd>
<title>Empire Burlesque</title>
<artist>Bob Dylan</artist>
<country>USA</country>
<company>Columbia</company>
<price>10.90</price>
<year>1985</year>
</cd>
.
.
.
</catalog>

重新整理瀏覽器,開啟開發者工具:

也可以在: https://www.coderbusy.com/demos/2021/1531/cdcatalog.xml 檢視線上示例。

從上面的操作可以看出,除錯 XLS 檔案的成本是很低的,開發者可以很容易對 XLS 檔案進行更改,並在短時間之內得到執行結果。

在 C# 中使用 XSLT 技術

在 C# 中,可以使用 XslCompiledTransform 進行 XSL 轉換。以下程式碼展示這個轉換過程:

XslCompiledTransform xsl = new XslCompiledTransform();
xsl.Load("cdcatalog.xsl");
var sb = new StringBuilder();
using (var sw = new StringWriter(sb))
{
  using (var xw = new XmlTextWriter(sw) { Formatting = Formatting.Indented })
  {
    xsl.Transform("cdcatalog.xml", xw);
  }
}
 
var xml = sb.ToString();
Console.WriteLine(xml);

以上程式碼會產生如下輸出:

<ArrayOfString xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:xsd="http://www.w3.org/2001/XMLSchema">
<string>Empire Burlesque</string>
<string>Hide your heart</string>
<string>Greatest Hits</string>
<string>Still got the blues</string>
<string>Eros</string>
.
.
.
</ArrayOfString>

反序列化 XML 字串

轉換 XML 不是目的,能直接拿到資料物件才是。以上的程式碼完成了格式轉換,接著需要對轉換好的 XML 字串反序列化:

var xmlSerializer = new XmlSerializer(typeof(List<string>));
using (var ms = new emoryStream(Encoding.UTF8.GetBytes(xml)))
{
    var list = (List<string>) xmlSerializer.Deserialize(ms);
    foreach (var item in list)
    {
        Console.WriteLine(item);
    }
}    

以上程式碼藉助 XmlSerializer 實現了反序列化功能,這會產生以下輸出:

Empire Burlesque
Hide your heart
Greatest Hits
Still got the blues
Eros
...

 

總結與原始碼

本文所述的轉換和反序列化技術已經在真實的生產環境中得到驗證,千萬級的資料處理也毫不費力。

本文包含的演示的程式碼和資料可以在 Gitee 上找到: https://gitee.com/coderbusy/demo/tree/master/hello-xslt/HelloXslt 。

相關文章