[Office開發系列] 誰說寫 Open XML文件產生程式一樣要寫落落長的程式碼?不妨玩玩 XSLT 吧。
在前兩篇 Open XML 文章中,我說明了使用程式的方式產生 Office 2007-2010 的 Open XML 文件,並且整合資料庫中的資料。若你有看過那兩篇文章的話,一定會對那個落落長的程式碼印象深刻,是的,若只想要以寫程式方式來處理的話,那麼長的程式碼是無可避免的,但其實我們有很多種作法,不一定只能依賴 coding directly (直接寫碼的方式執行工作),不要忘了,Open XML 也是一個 XML 文件,所有可以用在 XML 上的方法也可以在 Open XML 上如法炮製,而本文使用的是直接轉換的方法,也就是 XSLT (XML stylesheet/transform),利用 XSLT 會比直接寫碼不但快,而且程式也會非常簡潔。
我們一樣以前兩篇所用的範例文件檔來看,透過 OpenXML Productivity Tool,我們可以得到那個表格的 XML 結構:
Serial
Name
Unit
Qty
Price
AAA
AAA
AAA
AAA
AAA
為什麼我們要用 XSLT 來處理呢?因為 XSLT 基本上所負責的工作就是將來源的 XML 轉換成另一種格式的 XML (或是 HTML),在中大型應用系統,尤其是要求使用產業標準交換格式 (例如 HIPAA, RosettaNet, HL7 等) 的,在網路上傳遞幾乎全是 XML,而且由資料庫輸出的也都是 XML,若是用 XmlDocument 轉換,不但會太慢程式碼又落落長,這時 XSLT 就顯得非常重要,雖然它的指令很不容易寫,但它卻是處理與轉換 XML 格式文件的最好工具。
在本例中,我們會由資料庫中查詢出一個 XML 格式的資料結果:
1
Chai
1
1
10 boxes x 20 bags
18.0000
39
0
10
0
2
Chang
1
1
24 - 12 oz bottles
19.0000
17
40
25
0
…
依照這樣的結構,我們可以在 Visual Studio 專案中新增一個 DocumentTable.xslt:
並且在 XSLT 檔中加入下列的 XSLT 指令 (XSLT 指令部份我用紅字標示):
xmlns:msxsl="urn:schemas-microsoft-com:xslt" exclude-result-prefixes="msxsl"
>
Serial
Name
Unit
Qty
Price
XSLT 完成後,我們撰寫下列程式碼:
// 讀取資料庫並轉換成XML
private static string GetProductItemsXML()
{
SqlConnection conn = new SqlConnection("initial catalog=Northwind; integrated security=SSPI");
SqlCommand cmd = new SqlCommand("SELECT * FROM Products FOR XML PATH ('Product'), root ('Products')", conn);
conn.Open();
XmlReader reader = cmd.ExecuteXmlReader();
reader.Read();
string xmlData = reader.ReadOuterXml();
conn.Close();
return xmlData;
}
// 將資料庫讀出的XML使用XSLT轉換成OpenXML的格式。
private static string RenderOpenXMLTable(string XmlData)
{
XmlDocument doc = new XmlDocument();
XslCompiledTransform xslt = new XslCompiledTransform();
doc.LoadXml(XmlData);
xslt.Load("DocumentTable.xslt");
MemoryStream ms = new MemoryStream();
xslt.Transform(doc.DocumentElement, null, ms);
ms.Flush();
ms.Position = 0;
StreamReader reader = new StreamReader(ms);
string result = reader.ReadToEnd();
reader.Close();
XmlDocument docRender = new XmlDocument();
docRender.LoadXml(result);
result = docRender.DocumentElement.OuterXml;
doc = null;
docRender = null;
xslt = null;
return result;
}
然後在 Main 方法中加入下列程式 (改寫自前面的例子):
static void Main(string[] args)
{
FileStream fs = ReadTemplateFile();
WordprocessingDocument doc = WordprocessingDocument.Open(fs, true);
Document document = doc.MainDocumentPart.Document;
var tableXML = RenderOpenXMLTable(GetProductItemsXML());
var table = new Table(tableXML); // 使用生成的Open XML生成Table物件
document.Body.Append(table); // 將table物件加入文件本體。
doc.MainDocumentPart.Document.Save();
doc.Close();
fs.Close();
}
執行結果為:
執行結果與前面的例子完全相同,但是透過 XSLT,程式碼變得相當簡潔,您也可以將它應用在您的程式中。