ASP.NET 建立XML檔的方法
產生XML檔,比較常見有兩種方法
- 使用XmlSerializer序列化物件
- 傳統的System.XML命名空間提供處理 XML 的標準架構支援目標,及XmlElement、XmlNode等
環境
XML常使用Stream作為輸出入格式,這邊為了方便,直接使用LinqPad中的Console.Out
功能呈現結果
目標
官方XML範例
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
|
<?xml version="1.0" encoding="utf-8"?>
<PurchaseOrder xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:xsd="http://www.w3.org/2001/XMLSchema" xmlns="http://www.cpandl.com">
<ShipTo Name="Teresa Atkinson">
<Line1>1 Main St.</Line1>
<City>AnyTown</City>
<State>WA</State>
<Zip>00000</Zip>
</ShipTo>
<OrderDate>Wednesday, June 27, 2001</OrderDate>
<Items>
<OrderedItem>
<ItemName>Widget S</ItemName>
<Description>Small widget</Description>
<UnitPrice>5.23</UnitPrice>
<Quantity>3</Quantity>
<LineTotal>15.69</LineTotal>
</OrderedItem>
</Items>
<SubTotal>15.69</SubTotal>
<ShipCost>12.51</ShipCost>
<TotalCost>28.2</TotalCost>
</PurchaseOrder>
|
實作
使用XmlSerializer序列化物件
建立類別檔,或先撰寫一份XML草稿,使用Visual Studio 的「貼上XML做為類別」功能,再整理一份比較常見的類別檔
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
|
public class PurchaseOrder
{
public Address ShipTo { get; set; }
public string OrderDate { get; set; }
[XmlArray("Items")]
public List<OrderedItem> OrderedItems { get; set; }
public decimal SubTotal
{
get
{
return this.OrderedItems.Sum(x => x.LineTotal);
}
set { }
}
public decimal ShipCost { get; set; }
public decimal TotalCost
{
get
{
return this.SubTotal + this.ShipCost;
}
set { }
}
}
public class Address
{
[XmlAttribute]
public string Name { get; set; }
public string Line1 { get; set; }
public string City { get; set; }
public string State { get; set; }
public string Zip { get; set; }
}
public class OrderedItem
{
public string ItemName { get; set; }
public string Description { get; set; }
public decimal UnitPrice { get; set; }
public int Quantity { get; set; }
// C# 7.0
public decimal LineTotal
{
get => UnitPrice * Quantity;
set { }
}
// XMLSerializer的侷限性,屬性沒有setter無法序列化
// public decimal LineTotal => UnitPrice * Quantity;
}
|
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
|
void Main()
{
var order = new PurchaseOrder
{
ShipTo = new Address
{
Name = "Teresa Atkinson",
Line1 = "1 Main St.",
City = "AnyTown",
State = "WA",
Zip = "00000",
},
OrderDate = DateTime.Now.ToString(),
OrderedItems = new List<OrderedItem>
{
new OrderedItem
{
ItemName = "Widget S",
Description = "Small widget",
UnitPrice = (decimal)5.23,
Quantity = 3
}
},
ShipCost = (decimal)12.51,
};
// using System.Xml.Serialization
XmlSerializer serializer = new XmlSerializer(typeof(PurchaseOrder));
serializer.Serialize(Console.Out, order);
}
|
使用XML命名空間
雖然命名空間提供的類別非常的多,但常用只有XmlElement、XmlNode、XmlReader、XmlWriter等
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
|
void Main()
{
// 新增XML文件類別
XmlDocument xmlDoc = new XmlDocument();
// XML文件類別新增一個Element節點
XmlElement order = xmlDoc.CreateElement("PurchaseOrder");
xmlDoc.AppendChild(order);
XmlElement address = xmlDoc.CreateElement("ShipTo");
address.SetAttribute("Name","Teresa Atkinson"); // 設定屬性
order.AppendChild(address);
#region Address
XmlElement line1 = xmlDoc.CreateElement("Line1");
line1.InnerText = "1 Main St.";
address.AppendChild(line1);
XmlElement city = xmlDoc.CreateElement("City");
city.InnerText = "AnyTown";
// address節點底下
address.AppendChild(city);
XmlElement state = xmlDoc.CreateElement("State");
state.InnerText = "WA";
address.AppendChild(state);
XmlElement zip = xmlDoc.CreateElement("Zip");
zip.InnerText = "00000";
address.AppendChild(zip);
#endregion
XmlElement orderDate = xmlDoc.CreateElement("OrderDate");
orderDate.InnerText = DateTime.Now.ToString();
order.AppendChild(orderDate);
XmlElement items = xmlDoc.CreateElement("Items");
order.AppendChild(items);
XmlElement orderedItem = xmlDoc.CreateElement("OrderedItem");
items.AppendChild(orderedItem);
XmlElement itemName = xmlDoc.CreateElement("ItemName");
itemName.InnerText = "Widget S";
orderedItem.AppendChild(itemName);
// 除了XmlElement外 也可以用XmlNode 兩者效果是一樣的
XmlNode description = xmlDoc.CreateNode(XmlNodeType.Element,"Description",string.Empty);
description.InnerText = "Small widget";
orderedItem.AppendChild(description);
// ...(以下略)
XmlSerializer serializer = new XmlSerializer(typeof(XmlDocument));
serializer.Serialize(Console.Out, xmlDoc);
}
|
補充
清掉 XML Namespace(xmlns)
1
2
|
// 就是這行中的xmlns
<PurchaseOrder xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:xsd="http://www.w3.org/2001/XMLSchema">
|
1
2
3
4
5
6
7
|
XmlSerializerNamespaces emptyNS = new XmlSerializerNamespaces(new[] { new XmlQualifiedName("","") });
// 或
// XmlSerializerNamespaces emptyNS = new XmlSerializerNamespaces();
// emptyNS.Add("", "");
XmlSerializer serializer = new XmlSerializer(typeof(PurchaseOrder));
serializer.Serialize(Console.Out, order, emptyNS);
|
結論
因為JSON的普及,操作XML的機會越來越少,若單以建立XML檔,我優先選擇XmlSerializer,採用物件方式,程式碼較簡潔易懂,物件也易於後續的資料操作,而XmlDocument在修改、刪除節點內容時,個人覺得滿給力的
參考
余小章 @ 大內殿堂 - XML檔案基本操作-XmlDocument
https://dotblogs.com.tw/yc421206/2010/08/10/17108
Microsoft XML 序列化的範例
https://docs.microsoft.com/zh-tw/dotnet/standard/serialization/examples-of-xml-serialization
System.Xml 命名空間
https://docs.microsoft.com/zh-tw/dotnet/api/system.xml?view=netcore-3.1
檔案
使用XmlSerializer序列化物件.linq
使用XML命名空間.linq