1. 教程网站
http://www.w3school.com.cn/schema/index.asp
2. 为何使用XSD
Ø 可更容易地描述允许的文档内容
Ø 可更容易地验证数据的正确性
Ø 可更容易地与来自数据库的数据一并工作
Ø 可更容易地定义数据约束(data facets)
Ø 可更容易地定义数据模型(或称数据格式)
Ø 可更容易地在不同的数据类型间转换数据
3. XSD定义
1.1 minOccurs,maxOccurs
通过 schema,我们可使用 maxOccurs 和 minOccurs 属性来定义某个元素可能出现的次数。maxOccurs 定义某元素出现次数的最大值,而 minOccurs 则定义某元素出现次数的最小值。maxOccurs 和 minOccurs 的默认值都是 1!
1.2 XML例子
针对下面的XML实例,我们可以通过以下几种方式定义XSD。
<?xml version="1.0" encoding="utf-8"?>
<shiporder orderid="889923" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance">
<orderperson>George Bush</orderperson>
<shipto>
<name>John Adams</name>
<address>Oxford Street</address>
<city>London</city>
<country>UK</country>
</shipto>
<item>
<title>Empire Burlesque</title>
<note>Special Edition</note>
<quantity>1</quantity>
<price>10.90</price>
</item>
<item>
<title>Hide your heart</title>
<quantity>1</quantity>
<price>9.90</price>
</item>
</shiporder>
1.3 基本定义方式
<?xml version="1.0" encoding="utf-8" ?>
<xs:schema xmlns:xs="http://www.w3.org/2001/XMLSchema">
<xs:element name="shiporder">
<xs:complexType>
<xs:sequence>
<xs:element name="orderperson" type="xs:string"/>
<xs:element name="shipto">
<xs:complexType>
<xs:sequence>
<xs:element name="name" type="xs:string"/>
<xs:element name="address" type="xs:string"/>
<xs:element name="city" type="xs:string"/>
<xs:element name="country" type="xs:string"/>
</xs:sequence>
</xs:complexType>
</xs:element>
<xs:element name="item" maxOccurs="unbounded">
<xs:complexType>
<xs:sequence>
<xs:element name="title" type="xs:string"/>
<xs:element name="note" type="xs:string" minOccurs="0"/>
<xs:element name="quantity" type="xs:positiveInteger"/>
<xs:element name="price" type="xs:decimal"/>
</xs:sequence>
</xs:complexType>
</xs:element>
</xs:sequence>
<xs:attribute name="orderid" type="xs:string" use="required"/>
</xs:complexType>
</xs:element>
</xs:schema>
1.4 ref
定义元素,能够在其他地方通过ref进行引用。
<?xml version="1.0" encoding="utf-8" ?>
<xs:schema xmlns:xs="http://www.w3.org/2001/XMLSchema">
<xs:element name="orderperson" type="xs:string"/>
<xs:element name="name" type="xs:string"/>
<xs:element name="address" type="xs:string"/>
<xs:element name="city" type="xs:string"/>
<xs:element name="country" type="xs:string"/>
<xs:element name="title" type="xs:string"/>
<xs:element name="note" type="xs:string"/>
<xs:element name="quantity" type="xs:positiveInteger"/>
<xs:element name="price" type="xs:decimal"/>
<xs:attribute name="orderid" type="xs:string"/>
<xs:element name="shipto">
<xs:complexType>
<xs:sequence>
<xs:element ref="name"/>
<xs:element ref="address"/>
<xs:element ref="city"/>
<xs:element ref="country"/>
</xs:sequence>
</xs:complexType>
</xs:element>
<xs:element name="item">
<xs:complexType>
<xs:sequence>
<xs:element ref="title"/>
<xs:element ref="note" minOccurs="0"/>
<xs:element ref="quantity"/>
<xs:element ref="price"/>
</xs:sequence>
</xs:complexType>
</xs:element>
<xs:element name="shiporder">
<xs:complexType>
<xs:sequence>
<xs:element ref="orderperson"/>
<xs:element ref="shipto"/>
<xs:element ref="item" maxOccurs="unbounded"/>
</xs:sequence>
<xs:attribute ref="orderid" use="required"/>
</xs:complexType>
</xs:element>
</xs:schema>
1.5 named types
通过定义类型,可以指定元素的类型。
<?xml version="1.0" encoding="utf-8" ?>
<xs:schema xmlns:xs="http://www.w3.org/2001/XMLSchema">
<xs:simpleType name="stringtype">
<xs:restriction base="xs:string"/>
</xs:simpleType>
<xs:simpleType name="inttype">
<xs:restriction base="xs:positiveInteger"/>
</xs:simpleType>
<xs:simpleType name="dectype">
<xs:restriction base="xs:decimal"/>
</xs:simpleType>
<xs:simpleType name="orderidtype">
<xs:restriction base="xs:string">
<xs:pattern value="[0-9]{6}"/>
</xs:restriction>
</xs:simpleType>
<xs:complexType name="shiptotype">
<xs:sequence>
<xs:element name="name" type="stringtype"/>
<xs:element name="address" type="stringtype"/>
<xs:element name="city" type="stringtype"/>
<xs:element name="country" type="stringtype"/>
</xs:sequence>
</xs:complexType>
<xs:complexType name="itemtype">
<xs:sequence>
<xs:element name="title" type="stringtype"/>
<xs:element name="note" type="stringtype" minOccurs="0"/>
<xs:element name="quantity" type="inttype"/>
<xs:element name="price" type="dectype"/>
</xs:sequence>
</xs:complexType>
<xs:complexType name="shipordertype">
<xs:sequence>
<xs:element name="orderperson" type="stringtype"/>
<xs:element name="shipto" type="shiptotype"/>
<xs:element name="item" maxOccurs="unbounded" type="itemtype"/>
</xs:sequence>
<xs:attribute name="orderid" type="orderidtype" use="required"/>
</xs:complexType>
<xs:element name="shiporder" type="shipordertype"/>
</xs:schema>
2 .Net与XSD
2.1 通过XMLSchema方式
利用这种方式能够检查整个的XML文档中的所有问题,简单的代码如下:
using System;
using System.IO;
using System.Xml;
using System.Xml.Schema;
using System.Text;
namespace XSDStudy
{
public class XMLValidator
{
bool valid = false;
public bool Valid
{
get { return valid; }
}
StringBuilder sb;
public string Message
{
get { return sb.ToString(); }
}
bool backOnError = false;
public bool BackOnError
{
get { return backOnError; }
set { backOnError = valid; }
}
public XMLValidator()
{
}
public XMLValidator(bool backOnError)
{
this.backOnError = backOnError;
}
XmlTextReader xmlReader;
public void Validate(string xml,string xsd)
{
xmlReader = new XmlTextReader(new MemoryStream(Encoding.UTF8.GetBytes(xml)));
XmlReader xsdReader = XmlReader.Create(new MemoryStream(Encoding.UTF8.GetBytes(xsd)));
validate(xsdReader);
}
private void validate(XmlReader xsdReader)
{
sb = new StringBuilder();
valid = true;
try
{
XmlSchema schema = XmlSchema.Read(xsdReader, validationEventHandler);
XmlReaderSettings readerSettings = new XmlReaderSettings();
readerSettings.ValidationType = ValidationType.Schema;
readerSettings.ConformanceLevel = ConformanceLevel.Auto;
readerSettings.Schemas.Add(schema);
readerSettings.ValidationEventHandler += new ValidationEventHandler(validationEventHandler);
XmlReader objXmlReader = XmlReader.Create(xmlReader, readerSettings);
keepExecute = valid || !backOnError;
while (keepExecute && objXmlReader.Read())
{
////empty loop to check each node, when meet some invalid node will return.
}
}
catch (Exception ex)
{
sb.AppendLine(ex.Message);
}
}
bool keepExecute = true;
void validationEventHandler(object sender, ValidationEventArgs args)
{
valid = false;
keepExecute = valid || !backOnError;
sb.AppendLine(string.Format("Line:{0} - Position: {1} - {2}", xmlReader.LineNumber, xmlReader.LinePosition, args.Message));
}
}
}
2.2 直接利用XMLDocument
利用这种方式,只能检测出第一条错误的信息,然后就返回了,简单的代码如下:
using System;
using System.IO;
using System.Xml;
using System.Xml.Schema;
using System.Text;
using System.Xml.XPath;
namespace XSDStudy
{
public class XmlDocumentValidator
{
StringBuilder sb;
public string Message
{
get { return sb.ToString(); }
}
bool valid = false;
public bool Valid
{
get { return valid; }
}
public XmlDocumentValidator()
{
}
public void Validate(string xml, string xsd)
{
XmlTextReader xmlReader = new XmlTextReader(new MemoryStream(Encoding.UTF8.GetBytes(xml)));
XmlReader xsdReader = XmlReader.Create(new MemoryStream(Encoding.UTF8.GetBytes(xsd)));
validate(xmlReader, xsdReader);
}
private void validate(XmlReader xmlReader, XmlReader xsdReader)
{
sb = new StringBuilder();
valid = true;
try
{
XmlReaderSettings settings = new XmlReaderSettings();
settings.Schemas.Add(null, xsdReader);
settings.ValidationType = ValidationType.Schema;
XmlReader reader = XmlReader.Create(xmlReader, settings);
XmlDocument document = new XmlDocument();
document.Load(reader);
ValidationEventHandler eventHandler = new ValidationEventHandler(validationEventHandler);
document.Validate(eventHandler);
}
catch (Exception ex)
{
sb.AppendLine(ex.Message);
}
}
void validationEventHandler(object sender, ValidationEventArgs e)
{
valid = false;
switch (e.Severity)
{
case XmlSeverityType.Error:
sb.AppendLine(string.Format("Error: {0}", e.Message));
break;
case XmlSeverityType.Warning:
sb.AppendLine(string.Format("Warning {0}", e.Message));
break;
}
}
}
}
修改上述方法,使得可以直接针对文件进行验证。