Tải bản đầy đủ (.pdf) (10 trang)

Các giải pháp lập trình CSharp- P19 ppsx

Bạn đang xem bản rút gọn của tài liệu. Xem và tải ngay bản đầy đủ của tài liệu tại đây (2.62 MB, 10 trang )

181
Chương 5: XML
public bool ValidateXml(string xmlFilename, string schemaFilename) {
// 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) {
182
Chương 5: XML
failed = 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>
183
Chương 5: XML
<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;
184
Chương 5: XML
XmlSchemaCollection 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.
9.
S d ng XML Serialization v i các đ i t ng tùy bi nử ụ ớ ố ượ ế
S d ng XML Serialization v i các đ i t 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

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.
185
Chương 5: XML
Để sử dụng XML serialization, trước hết bạn phải đánh dấu các đối tượng dữ liệu với các đặc
tí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

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;
186
Chương 5: XML
this.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 Pascal
1

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,
1

Pascal 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
187
Chương 5: XML
tuần tự hóa đối tượng thành tài liệu XML, giải tuần tự hóa tài liệu thành đối tượng, và rồi hiển
thị 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();
}
188
Chương 5: XML
}
10.
10.

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

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.
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.
189

Chương 5: XML
Mục 5.10 đã giới thiệu tiện ích dòng lệnh xsd.exe, tiện ích này có thể được sử dụng để tạo
XML 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

productCalalog
. Hai
lớp này tương tự với hai lớp đã được tạo trong mục 5.9.
12.
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=" /> 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">
190
Chương 5: XML
<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

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>

×