XML(可延伸標記語言)是**結構化資料交換與儲存**的通用格式。ASP.NET 提供兩大原生引擎處理 XML:
System.Xml.Linq):函數式建構/查詢/轉換,語法優雅、效能優異、支援串流處理大型 XML。<?xml version="1.0" encoding="utf-8"?>
<Courses>
<Course Id="1" Category="Development">
<Title>ASP.NET Core 實戰</Title>
<Author>張三</Author>
<Price>1200</Price>
<Tags><Tag>C#</Tag><Tag>Web</Tag></Tags>
</Course>
<Course Id="2" Category="Cloud">
<Title>Azure 雲端架構</Title>
<Author>李四</Author>
<Price>1500</Price>
<Tags><Tag>Azure</Tag><Tag>DevOps</Tag></Tags>
</Course>
</Courses>
protected void Page_Load(object sender, EventArgs e)
{
if (!IsPostBack)
{
var ds = new DataSet();
ds.ReadXml(Server.MapPath("~/App_Data/Courses.xml")); // 自動推斷 Schema
// DataSet 可能產生多個 DataTable (巢狀元素會拆成關聯表)
// 主表通常是第一個
gvCourses.DataSource = ds.Tables[0].DefaultView;
gvCourses.DataBind();
}
}
public void SaveCourses(DataTable dt)
{
var ds = new DataSet();
ds.Tables.Add(dt.Copy());
ds.WriteXml(Server.MapPath("~/App_Data/Courses.xml"), XmlWriteMode.WriteSchema); // 含結構描述
}
var ds = new DataSet();
ds.ReadXmlSchema(Server.MapPath("~/App_Data/Courses.xsd")); // 先載入 XSD
ds.ReadXml(Server.MapPath("~/App_Data/Courses.xml")); // 再載入資料
// 此時 ds.Tables["Course"].Columns["Price"].DataType == typeof(decimal)
XDocument doc = XDocument.Load(Server.MapPath("~/App_Data/Courses.xml"));
// 查詢所有開發類課程標題
var devTitles = doc.Descendants("Course")
.Where(c => (string)c.Attribute("Category") == "Development")
.Select(c => (string)c.Element("Title"));
// 輸出: ASP.NET Core 實戰
foreach (var t in devTitles) Console.WriteLine(t);
var newDoc = new XDocument(
new XDeclaration("1.0", "utf-8", "yes"),
new XElement("Courses",
from c in GetCourseDtos()
select new XElement("Course",
new XAttribute("Id", c.Id),
new XAttribute("Category", c.Category),
new XElement("Title", c.Title),
new XElement("Author", c.Author),
new XElement("Price", c.Price),
new XElement("Tags",
from tag in c.Tags select new XElement("Tag", tag))
)
)
);
newDoc.Save(Server.MapPath("~/App_Data/NewCourses.xml"));
var doc = XDocument.Load(path);
var course = doc.Descendants("Course").FirstOrDefault(c => (int)c.Attribute("Id") == 1);
if (course != null)
{
course.Element("Price").SetValue(1300); // 修改價格
course.Element("Tags").Add(new XElement("Tag", "MVC")); // 新增標籤
doc.Save(path);
}
XmlReader + LINQ)// 僅讀取 Course 元素,不將整份文件載入記憶體
using (var reader = XmlReader.Create(Server.MapPath("~/App_Data/HugeCourses.xml")))
{
reader.MoveToContent();
while (reader.Read())
{
if (reader.NodeType == XmlNodeType.Element && reader.Name == "Course")
{
var courseElement = XElement.ReadFrom(reader) as XElement;
var price = (int)courseElement.Element("Price");
if (price > 1000)
ProcessExpensiveCourse(courseElement);
}
}
}
var schemas = new XmlSchemaSet();
schemas.Add("", XmlReader.Create(Server.MapPath("~/App_Data/Courses.xsd")));
var doc = XDocument.Load(Server.MapPath("~/App_Data/Courses.xml"));
bool isValid = true;
doc.Validate(schemas, (o, e) =>
{
_logger.Error($"XML 驗證失敗: {e.Message}");
isValid = false;
});
if (isValid) ProcessValidDocument(doc);
[XmlRoot("Course")]
public class CourseDto
{
[XmlAttribute("Id")] public int Id { get; set; }
[XmlAttribute("Category")] public string Category { get; set; }
[XmlElement("Title")] public string Title { get; set; }
[XmlElement("Author")] public string Author { get; set; }
[XmlElement("Price")] public decimal Price { get; set; }
[XmlArray("Tags")] [XmlArrayItem("Tag")] public List Tags { get; set; }
}
// 序列化
var serializer = new XmlSerializer(typeof(List), new XmlRootAttribute("Courses"));
using (var writer = XmlWriter.Create(path, new XmlWriterSettings { Indent = true }))
serializer.Serialize(writer, courses);
// 反序列化
List courses;
using (var reader = XmlReader.Create(path))
courses = (List)serializer.Deserialize(reader);
[DataContract(Namespace = "")]
public class CourseDto
{
[DataMember(Order = 1)] public int Id { get; set; }
[DataMember(Order = 2)] public string Title { get; set; }
// ...
}
// 二進制/XML/JSON 通用
var serializer = new DataContractSerializer(typeof(List));
using (var ms = new MemoryStream())
{
serializer.WriteObject(ms, courses); // 預設 XML
// serializer.WriteObject(ms, courses, new DataContractJsonSerializerSettings()); // JSON
}
| 場景 | 推薦引擎 | 理由 |
|---|---|---|
| 小型 XML (< 1MB) 直接綁定 GridView/Repeater | DataSet | 零程式碼、自動 Schema 推斷、雙向綁定 |
| 複雜查詢、轉換、建構、大型 XML (> 10MB) | LINQ to XML | 串流支援、函數式語法、記憶體效率高 |
| Web Service 回傳 / 設定檔 / 物件持久化 | XmlSerializer / DataContractSerializer | 強型別、版本容忍、契約優先 |
| 需 XSD 驗證 | LINQ to XML + Validate() | 標準化驗證、錯誤報告豐富 |
XElement 查詢需包含命名空間 XNamespace ns = "..."; doc.Descendants(ns + "Course")。Encoding.UTF8,避免中文亂碼。XmlReader 串流模式。