Console.WriteLine"Validation error: " + args.Message; Console.WriteLine; } } Dưới đây là cách sử dụng lớp này để xác nhận tính hợp lệ của danh mục sản phẩm: using System; public class
Trang 1// Tạo validator.
XmlTextReader r = new XmlTextReader(xmlFilename);
XmlValidatingReader validator = new XmlValidatingReader(r);
validator.ValidationType = ValidationType.Schema;
// Nạp Schema vào validator
XmlSchemaCollection schemas = new XmlSchemaCollection();
schemas.Add(null, schemaFilename);
validator.Schemas.Add(schemas);
// Thiết lập phương thức thụ lý sự kiện validation
validator.ValidationEventHandler +=
new ValidationEventHandler(ValidationEventHandler);
failed = false;
try {
// Đọc tất cả dữ liệu XML
while (validator.Read())
{}
}catch (XmlException err) {
// Điều này xảy ra khi tài liệu XML có chứa ký tự bất
// hợp lệ hoặc các thẻ lồng nhau hay đóng không đúng
Console.WriteLine("A critical XML error has occurred.");
Console.WriteLine(err.Message);
failed = true;
}finally {
validator.Close();
}
return !failed;
}
private void ValidationEventHandler(object sender,
ValidationEventArgs args) {
Trang 2failed = true;
// Hiển thị lỗi validation
Console.WriteLine("Validation error: " + args.Message);
Console.WriteLine();
}
}
Dưới đây là cách sử dụng lớp này để xác nhận tính hợp lệ của danh mục sản phẩm:
using System;
public class ValidateXml {
private static void Main() {
ConsoleValidator consoleValidator = new ConsoleValidator();
Console.WriteLine("Validating ProductCatalog.xml.");
bool success = consoleValidator.ValidateXml("ProductCatalog.xml",
"ProductCatalog.xsd");
if (!success) {
Console.WriteLine("Validation failed.");
}else {
Console.WriteLine("Validation succeeded.");
}
Console.ReadLine();
}
}
Nếu tài liệu hợp lệ thì sẽ không có thông báo nào xuất hiện, và biến success sẽ được thiết lập thành true Nhưng xét xem điều gì sẽ xảy ra nếu bạn sử dụng một tài liệu phá vỡ các quy tắc
Schema, chẳng hạn file ProductCatalog_Invalid.xml như sau:
<?xml version="1.0" ?>
<productCatalog>
<catalogName>Acme Fall 2003 Catalog</catalogName>
<expiryDate>Jan 1, 2004</expiryDate>
Trang 3<products>
<product id="1001">
<productName>Magic Ring</productName>
<productPrice>$342.10</productPrice>
<inStock>true</inStock>
</product>
<product id="1002">
<productName>Flying Carpet</productName>
<productPrice>982.99</productPrice>
<inStock>Yes</inStock>
</product>
</products>
</productCatalog>
Nếu bạn kiểm tra tài liệu này, biến success sẽ được thiết lập thành false và kết xuất sẽ cho biết các lỗi:
Validating ProductCatalog_Invalid.xml
Validation error: The 'expiryDate' element has an invalid value according to its data type An error occurred at file:///I:/CSharp/Chuong05/05-08/
bin/Debug/ProductCatalog_Invalid.xml, (4, 30)
Validation error: The 'productPrice' element has an invalid value according to its data type An error occurred at file:///I:/CSharp/Chuong05/05-08/
bin/Debug/ProductCatalog_Invalid.xml, (9, 36)
Validation error: The 'inStock' element has an invalid value according to its data type An error occurred at file:///I:/CSharp/Chuong05/05-08/
bin/Debug/ProductCatalog_Invalid.xml, (15, 27)
Validation failed
Cuối cùng, nếu muốn xác nhận tính hợp lệ của một tài liệu XML và rồi xử lý nó, bạn có thể sử
dụng XmlValidatingReader để quét tài liệu khi nó được đọc vào một XmlDocument trong-bộ-nhớ:
XmlDocument doc = new XmlDocument();
XmlTextReader r = new XmlTextReader("ProductCatalog.xml");
XmlValidatingReader validator = new XmlValidatingReader(r);
// Nạp Schema vào validator
validator.ValidationType = ValidationType.Schema;
Trang 4XmlSchemaCollection schemas = new XmlSchemaCollection();
schemas.Add(null, "ProductCatalog.xsd");
validator.Schemas.Add(schemas);
// Nạp và kiểm tra tài liệu cùng một lúc
try {
doc.Load(validator);
// (Validation thành công.)
}catch (XmlSchemaException err) {
// (Validation thất bại.)
}
9. S d ng XML Serialization v i các đ i t S d ng XML Serialization v i các đ i t ử ụ ử ụ ớ ớ ố ượ ố ượ ng tùy bi n ng tùy bi n ế ế
Bạn cần sử dụng XML như một định dạng tuần tự hóa (serialization format) Tuy
nhiên, bạn không muốn xử lý XML trực tiếp trong mã lệnh, mà muốn tương tác
với dữ liệu bằng các đối tượng tùy biến.
Sử dụng lớp System.Xml.Serialization.XmlSerializer để chuyển dữ liệu từ đối
tượng của bạn sang XML, và ngược lại Bạn cũng có thể đánh dấu mã lệnh của lớp bằng các đặc tính để tùy biến biểu diễn XML của nó.
Lớp XmlSerializer cho phép chuyển các đối tượng thành dữ liệu XML, và ngược lại Lớp này
đủ thông minh để tạo đúng các mảng khi nó tìm thấy các phần tử lồng bên trong.
Các yêu cầu khi sử dụng XmlSerializer:
• XmlSerializer chỉ tuần tự hóa các thuộc tính và các biến công khai
• Các lớp cần tuần tự hóa phải chứa một phương thức khởi dựng mặc định không có đối
số XmlSerializer sẽ sử dụng phương thức khởi dựng này khi tạo đối tượng mới trong quá trình giải tuần tự hóa.
• Các thuộc tính của lớp phải là khả-đọc (readable) và khả-ghi (writable) Đó là vì
XmlSerializer sử dụng hàm truy xuất thuộc tính get để lấy thông tin và hàm truy xuất
thuộc tính set để phục hồi dữ liệu sau khi giải tuần tự hóa
Bạn cũng có thể lưu trữ các đối tượng theo định dạng dựa-trên-XML bằng cách
sử dụng NET Serialization và System.Runtime.Serialization.Formatters.Soap SoapFormatter Trong trường hợp này, bạn chỉ cần làm cho lớp của bạn trở thành khả-tuần-tự-hóa, không cần cung cấp phương thức khởi dựng mặc định hay bảo đảm tất cả các thuộc tính là khả ghi Tuy nhiên, cách này không cho bạn
quyền kiểm soát trên định dạng XML đã-được-tuần-tự-hóa.
Trang 5tính cho biết phép ánh xạ sang XML Các đặc tính này thuộc không gian tên
System.Xml.Serialization và bao gồm:
• XmlRoot—cho biết tên phần tử gốc của file XML Theo mặc định, XmlSerializer sẽ sử dụng tên của lớp Đặc tính này có thể được áp dụng khi khai báo lớp.
• XmlElement—cho biết tên phần tử dùng cho một thuộc tính hay biến công khai Theo mặc định, XmlSerializer sẽ sử dụng tên của thuộc tính hay biến công khai.
• XmlAttribute—cho biết một thuộc tính hay biến công khai sẽ được tuần tự hóa thành một đặc tính (không phải phần tử), và chỉ định tên đặc tính.
• XmlEnum—cấu hình phần text sẽ được sử dụng khi tuần tự hóa các giá trị liệt kê Nếu bạn không sử dụng XmlEnum, tên của hằng liệt kê sẽ được sử dụng.
• XmlIgnore—cho biết một thuộc tính hay biến công khai sẽ không được tuần tự hóa
Ví dụ, xét danh mục sản phẩm đã được trình bày trong mục 5.1 Bạn có thể mô tả tài liệu
XML này bằng các đối tượng ProductCatalog và Product như sau:
using System;
using System.Xml.Serialization;
[XmlRoot("productCatalog")]
public class ProductCatalog {
[XmlElement("catalogName")]
public string CatalogName;
// Sử dụng kiểu dữ liệu ngày (bỏ qua phần giờ)
[XmlElement(ElementName="expiryDate", DataType="date")]
public DateTime ExpiryDate;
// Cấu hình tên thẻ
[XmlArray("products")]
[XmlArrayItem("product")]
public Product[] Products;
public ProductCatalog() {
// Phương thức khởi dựng mặc định (dùng khi giải tuần tự hóa)
}
public ProductCatalog(string catalogName, DateTime expiryDate) {
this.CatalogName = catalogName;
Trang 6this.ExpiryDate = expiryDate;
}
}
public class Product {
[XmlElement("productName")]
public string ProductName;
[XmlElement("productPrice")]
public decimal ProductPrice;
[XmlElement("inStock")]
public bool InStock;
[XmlAttributeAttribute(AttributeName="id", DataType="integer")]
public string Id;
public Product() {
// Phương thức khởi dựng mặc định (dùng khi giải tuần tự hóa)
}
public Product(string productName, decimal productPrice) {
this.ProductName = productName;
this.ProductPrice = productPrice;
}
}
Chú ý rằng, các lớp này sử dụng các đặc tính XML Serialization để đổi tên phần tử (sử dụng kiểu ký hiệu Pascal1 trong tên thành viên lớp, và kiểu ký hiệu lưng lạc đà2 trong tên thẻ XML),
cho biết các kiểu dữ liệu không rõ ràng, và chỉ định các phần tử <product> sẽ được lồng bên trong <productCatalog> như thế nào.
Bằng cách sử dụng các lớp tùy biến này và đối tượng XmlSerializer, bạn có thể chuyển XML thành các đối tượng và ngược lại Đoạn mã dưới đây tạo một đối tượng ProductCatalog mới,
1Pascal casing: Mẫu tự đầu tiên của các chữ đều viết hoa, ví dụ SomeOtherName
2 Camel casing: Mẫu tự đầu tiên của chữ đầu viết thường, mẫu tự đầu tiên của các chữ đi sau viết hoa, ví
dụ someOtherName
Trang 7thị tài liệu này:
using System;
using System.Xml;
using System.Xml.Serialization;
using System.IO;
public class SerializeXml {
private static void Main() {
// Tạo danh mục sản phẩm
ProductCatalog catalog = new ProductCatalog("New Catalog",
DateTime.Now.AddYears(1));
Product[] products = new Product[2];
products[0] = new Product("Product 1", 42.99m);
products[1] = new Product("Product 2", 202.99m);
catalog.Products = products;
// Tuần tự hóa danh mục ra file
XmlSerializer serializer =
new XmlSerializer(typeof(ProductCatalog));
FileStream fs =
new FileStream("ProductCatalog.xml", FileMode.Create);
serializer.Serialize(fs, catalog);
fs.Close();
catalog = null;
// Giải tuần tự hóa danh mục từ file
fs = new FileStream("ProductCatalog.xml", FileMode.Open);
catalog = (ProductCatalog)serializer.Deserialize(fs);
// Tuần tự hóa danh mục ra cửa sổ Console
serializer.Serialize(Console.Out, catalog);
Console.ReadLine();
}
Trang 810. T o XML Schema cho m t l p NET T o XML Schema cho m t l p NET ạ ạ ộ ớ ộ ớ
Bạn cần tạo một XML Schema dựa trên một hay nhiều lớp C# Điều này cho
phép bạn kiểm tra tính hợp lệ của các tài liệu XML trước khi giải tuần tự hóa
chúng với XmlSerializer.
Sử dụng tiện ích dòng lệnh XML Schema Definition Tool (xsd.exe—đi kèm với
.NET Framework) Chỉ định tên của assembly làm đối số dòng lệnh, và thêm đối
số /t:[TypeName] để cho biết kiểu cần chuyển đổi.
Mục 5.9 đã trình bày cách sử dụng XmlSerializer để tuần tự hóa đối tượng NET thành XML,
và giải tuần tự hóa XML thành đối tượng NET Nhưng nếu muốn sử dụng XML như một
phương cách để tương tác với các ứng dụng khác, quy trình nghiệp vụ, hay các ứng dụng
phi-Framework, bạn sẽ cần xác nhận tính hợp lệ của XML trước khi giải tuần tự hóa nó Bạn cũng
sẽ cần tạo một tài liệu XML Schema định nghĩa cấu trúc và các kiểu dữ liệu được sử dụng trong định dạng XML của bạn, để các ứng dụng khác có thể làm việc với nó Một giải pháp là
sử dụng tiện ích dòng lệnh xsd.exe.
Tiện ích xsd.exe đi kèm với NET Framework Nếu đã cài đặt Microsoft Visual Studio NET, bạn sẽ tìm thấy nó trong thư mục C:\Program Files\Microsoft Visual Studio NET\FrameworkSDK\Bin Tiện ích xsd.exe có thể tạo ra XML Schema từ một assembly đã được biên dịch Bạn chỉ cần cung cấp tên file và cho biết lớp mô tả tài liệu XML với đối số
/t:[TypeName].
Ví dụ, xét các lớp ProductCatalog và Product đã được trình bày trong mục 5.9 Bạn có thể tạo
XML Schema cho một danh mục sản phẩm với dòng lệnh sau:
xsd 05-09.exe /t:ProductCatalog
Bạn chỉ cần chỉ định lớp ProductCatalog trên dòng lệnh, vì lớp này mô tả tài liệu XML XML
Schema được tạo ra trong ví dụ này (có tên mặc định là schema0.xsd) sẽ mô tả đầy đủ một
danh mục sản phẩm, với các item sản phẩm lồng bên trong Bây giờ, bạn có thể sử dụng XmlValidatingReader (đã được trình bày trong mục 5.8) để kiểm tra tính hợp lệ của tài liệu
XML dựa vào XML Schema này.
11. T o l p t m t XML Schema T o l p t m t XML Schema ạ ớ ừ ộ ạ ớ ừ ộ
Bạn cần tạo một hay nhiều lớp C# dựa trên một XML Schema; để sau đó, bạn có
thể tạo một tài liệu XML theo định dạng phù hợp bằng các đối tượng này và
XmlSerializer.
Sử dụng tiện ích dòng lệnh xsd.exe (đi kèm với NET Framework) Chỉ định tên
file Schema làm đối số dòng lệnh, và thêm đối số /c để cho biết bạn muốn tạo mã lệnh cho lớp.
Trang 9XML Schema dựa trên định nghĩa lớp Quá trình ngược lại (tạo mã lệnh C# dựa trên một tài liệu XML Schema) cũng có thể xảy ra Việc này hữu ích khi bạn muốn ghi một định dạng XML nào đó, nhưng lại không muốn tạo tài liệu này bằng cách ghi từng nút một với lớp
XmlDocument hay XmlTextWriter Thay vào đó, bằng cách sử dụng xsd.exe, bạn có thể tạo ra
một tập đầy đủ các đối tượng NET Kế đó, bạn có thể tuần tự hóa các đối tượng này thành biểu diễn XML bằng XmlSerializer, như được mô tả trong mục 5.9.
Để tạo mã lệnh từ một XML Schema, bạn chỉ cần cung cấp tên file Schema và thêm đối số /c
để cho biết bạn muốn tạo ra lớp Ví dụ, xét XML Schema đã được trình bày trong mục 5.8 Bạn có thể tạo mã lệnh C# từ Schema này với dòng lệnh sau:
xsd ProductCatalog.xsd /c
Lệnh này sẽ tạo ra một file (ProductCatalog.cs) gồm hai lớp: Product và productCalalog Hai
lớp này tương tự với hai lớp đã được tạo trong mục 5.9.
12. Th c hi n phép bi n đ i XSL Th c hi n phép bi n đ i XSL ự ệ ự ệ ế ổ ế ổ
Bạn cần biến đổi một tài liệu XML thành một tài liệu khác bằng XSLT stylesheet.
Sử dụng lớp System.Xml.Xsl.XslTransform Nạp XSLT stylesheet bằng phương
thức XslTransform.Load, và tạo tài liệu kết xuất bằng phương thức Transform (cần cung cấp tài liệu nguồn).
XSLT (hay XSL Transforms) là một ngôn ngữ dựa-trên-XML, được thiết kế để biến đổi một tài liệu XML thành một tài liệu khác XSLT có thể được sử dụng để tạo một tài liệu XML mới với
cùng dữ liệu nhưng được sắp xếp theo một cấu trúc khác hoặc để chọn một tập con dữ liệu trong một tài liệu Nó cũng có thể được sử dụng để tạo một kiểu tài liệu có cấu trúc khác
XSLT thường được sử dụng theo cách này để định dạng một tài liệu XML thành một trang HTML.
XSLT là một ngôn ngữ đa năng, và việc tạo XSL Transforms vượt quá phạm vi quyển sách này Tuy nhiên, bạn có thể học cách tạo các tài liệu XSLT đơn giản bằng cách xem một ví dụ
cơ bản Mục này sẽ biến đổi tài liệu orders.xml (đã được trình bày trong mục 5.6) thành một tài liệu HTML và rồi hiển thị kết quả Để thực hiện phép biến đổi này, bạn sẽ cần XSLT stylesheet như sau:
<?xml version="1.0" encoding="UTF-8" ?>
<xsl:stylesheet xmlns:xsl="http://www.w3.org/1999/XSL/Transform"
version="1.0" >
<xsl:template match="Order">
<html><body><p>
Order <b><xsl:value-of select="Client/@id"/></b>
for <xsl:value-of select="Client/Name"/></p>
<table border="1">
Trang 10<td>ID</td><td>Name</td><td>Price</td>
<xsl:apply-templates select="Items/Item"/>
</table></body></html>
</xsl:template>
<xsl:template match="Items/Item">
<tr>
<td><xsl:value-of select="@id"/></td>
<td><xsl:value-of select="Name"/></td>
<td><xsl:value-of select="Price"/></td>
</tr>
</xsl:template>
</xsl:stylesheet>
Về cơ bản, mọi XSL stylesheet gồm một tập các template Mỗi template so trùng với các phần
tử trong tài liệu nguồn và rồi mô tả các phần tử được so trùng để tạo nên tài liệu kết quả Để
so trùng template, tài liệu XSLT sử dụng biểu thức XPath, như được mô tả trong mục 5.6 Stylesheet vừa trình bày ở trên (orders.xslt) gồm hai template (là các con của phần tử stylesheet gốc) Template đầu tiên trùng khớp với phần tử Order gốc Khi bộ xử lý XSLT tìm
thấy một phần tử Order, nó sẽ ghi ra các thẻ cần thiết để bắt đầu một bảng HTML với các tiêu
đề cột thích hợp và chèn dữ liệu về khách hàng bằng lệnh value-of (ghi ra kết quả dạng text
của một biểu thức XPath) Trong trường hợp này, các biểu thức XPath (Client/@id và
Client/Name) trùng với đặc tính id và phần tử Name
Kế tiếp, lệnh apply-templates được sử dụng để phân nhánh và xử lý các phần tử Item nằm trong Điều này là cần thiết vì có thể có nhiều phần tử Item Mỗi phần tử Item được so trùng bằng biểu thức Items/Item (nút gốc Order không được chỉ định vì Order chính là nút hiện tại)
Cuối cùng, các thẻ cần thiết sẽ được ghi ra để kết thúc tài liệu HTML.
Nếu thực thi phép biến đổi này trên file orders.xml (đã trình bày trong mục 5.6), bạn sẽ nhận được kết quả (tài liệu HTML) như sau:
<html>
<body>
<p>
Order <b>ROS-930252034</b>
for Remarkable Office Supplies</p>
<table border="1">
<td>ID</td>
<td>Name</td>