在C#开发过程中,经常需要将对象序列化为XML文件,或者从已有的XML文件生成XSD(XML Schema Definition)文件,以及验证XML文件是否符合XSD定义的规则。本文将详细介绍这三个过程的实现方法。
假设有以下C#对象,希望将它们序列化为XML。
public class OrderList {
public List<Order> Orders { get; set; }
}
public class Order {
public OrderSummary OrderSummary { get; set; }
public Customer Customer { get; set; }
}
public class Address {
public string AddressLine1 { get; set; }
public string AddressLine2 { get; set; }
public string AddressLine3 { get; set; }
public string City { get; set; }
public string County { get; set; }
public string PostCode { get; set; }
}
public class Customer {
public string Title { get; set; }
public string FirstName { get; set; }
public string LastName { get; set; }
public string Email { get; set; }
public string Phone { get; set; }
}
public class OrderSummary {
public List<OrderLine> OrderLines { get; set; }
public Address DeliveryAddress { get; set; }
public DateTime DeliveryDate { get; set; }
}
public class OrderLine {
public decimal ItemQuanity { get; set; }
public string ItemName { get; set; }
}
要将这些对象保存为XML文件,可以使用以下代码:
public static void CreateXmlFile(string filename) {
Address add = new Address {
AddressLine1 = "AddressLine1",
AddressLine2 = "AddressLine2",
AddressLine3 = "AddressLine3",
City = "City",
County = "County",
PostCode = "PostCode"
};
Customer cust = new Customer {
Email = "Email",
FirstName = "John",
LastName = "Barnes",
Phone = "13311",
Title = "Mr"
};
OrderList orders = new OrderList();
var orderSummary = new OrderSummary {
DeliveryAddress = add,
DeliveryDate = DateTime.Now,
OrderLines = new List<OrderLine> {
new OrderLine { ItemQuanity = 150, ItemName = "TestItem1" },
new OrderLine { ItemQuanity = 250, ItemName = "TestItem2" },
new OrderLine { ItemQuanity = 4, ItemName = "TestItem3" },
},
};
Order order1 = new Order();
order1.Customer = cust;
order1.OrderSummary = orderSummary;
orders.Orders.Add(order1);
XmlSerializer xmlSerializer = new XmlSerializer(typeof(OrderList));
using (FileStream stream = File.OpenWrite(filename)) {
xmlSerializer.Serialize(stream, orders);
}
}
有多种方法可以从XML文件生成XSD文件,这里选择使用C#编程方式生成XSD文件。
public static void CreateSchemaFromXml(string fileName) {
XmlSerializer xmlSerializer = new XmlSerializer(typeof(OrderList));
XmlSchemas schemas = new XmlSchemas();
XmlSchemaExporter exporter = new XmlSchemaExporter(schemas);
XmlTypeMapping mapping = new XmlReflectionImporter().ImportTypeMapping(typeof(OrderList));
exporter.ExportTypeMapping(mapping);
var schemasData = TrimSchema(schemas);
using (FileStream stream = File.OpenWrite(fileName)) {
schemasData.First().Write(stream);
}
}
private static List<XmlSchema> TrimSchema(XmlSchemas schemas) {
List<XmlSchema> schemasData = new List<XmlSchema>(
schemas.Where(s => s.TargetNamespace != "http://www.w3.org/2001/XMLSchema" &&
s.TargetNamespace != "http://microsoft.com/wsdl/types/")
);
return schemasData;
}
以上代码将生成一个有效的XSD文件,可以对其进行修改以添加更多的限制。
使用以下测试代码可以轻松实现XML文件的验证。
using System;
using System.Collections.Generic;
using System.IO;
using System.Linq;
using System.Reflection;
using System.Text;
using System.Threading.Tasks;
using System.Xml.Linq;
using System.Xml.Schema;
using NUnit.Framework;
namespace XmlTests {
[TestFixture]
public class StaticXmlFileTests {
[TestCase(@"\Xml\BadAgainstSchema\OrdersBADExampleFileNoOrderSummary.xml", false)]
[TestCase(@"\Xml\BadAgainstSchema\OrdersBADExampleFile_AddressLineTooLong.xml", false)]
[TestCase(@"\Xml\Good\OrdersGOODExampleFile_FullFeatureSet.xml", true)]
[TestCase(@"\Xml\Good\OrdersGOODExampleFile_MultipleOrderLines.xml", true)]
[TestCase(@"\Xml\Good\OrdersGOODExampleFile_MultipleOrders.xml", true)]
[TestCase(@"\Xml\Good\OrdersGOODExampleFile_SingleOrder.xml", true)]
[TestCase(@"\Xml\Good\OrdersGOODExampleFile_SingleOrderLine.xml", true)]
public void TestFileProducesExpectedSchemaValidationResult(string filename, bool exepectedValidationResult) {
var xmlFile = ObtainFullFilePath(filename);
var xsdFile = ObtainFullFilePath(@"\Xml\OrdersExampleFile.xsd");
var xdoc = XDocument.Load(xmlFile);
var schemas = new XmlSchemaSet();
using (FileStream stream = File.OpenRead(xsdFile)) {
schemas.Add(XmlSchema.Read(stream, (s, e) => {
var x = e.Message;
}));
}
bool isvalid = true;
StringBuilder sb = new StringBuilder();
try {
xdoc.Validate(schemas, (s, e) => {
isvalid = false;
sb.AppendLine(string.Format("Line : {0}, Message : {1}", e.Exception.LineNumber, e.Exception.Message));
});
} catch (XmlSchemaValidationException) {
isvalid = false;
}
var validationErrors = sb.ToString();
Assert.AreEqual(exepectedValidationResult, isvalid);
if (exepectedValidationResult) {
Assert.AreEqual(string.Empty, validationErrors);
} else {
Assert.AreNotEqual(string.Empty, validationErrors);
}
}
private string ObtainFullFilePath(string fileName) {
var path = TestContext.CurrentContext.TestDirectory;
return string.Format("{0}{1}", path, fileName);
}
}
}