XML简明教程(7)

XML验证之Schema


就像前面的文章所说的,通过DTD我们可以很容易的判断要验证的XML是否符合我们所定义的规范(元素之间的关系,属性的取值是否正确)但是如果要验证元素的内容DTD就无能为力了,于是人们研究了新的验证方法——Schema

除了上面的优势之外Schema相对于DTD而言更令人兴奋的是其自身就是一个良好形式的XML文档,这样一来编写Schema就非常容易了。相对于自己有一套独立的语法DTD而言,无论是编写还是维护起来都是非常困难的。

一个Schema文件就是一个XML文件所以所编写一个XML对应的Schema的过程就是对照着XMLXML,这样的话编写Schema是非常容易的。下面演示如何对照XML编写其对应的Schema

原XML文件(test2.xml)

<?xml version="1.0"encoding="ISO-8859-1"?>
 
<shiporder orderid="889923"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:noNamespaceSchemaLocation="shiporder.xsd">
 <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>
 


对于上面的这个XML下面我们开始创建一个Schema。遵从的原则就是原来的XML怎么写那么其对应的Schema就怎么描述,就像你在和一个人面对面的描述一样。

Schema代码如下(shiporder.xsd)

 
<?xml version="1.0"encoding="ISO-8859-1" ?>
<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:elementname="name" type="xs:string"/>
      <xs:elementname="address" type="xs:string"/>
      <xs:elementname="city" type="xs:string"/>
      <xs:elementname="country" type="xs:string"/>
     </xs:sequence>
    </xs:complexType>
   </xs:element>
   <xs:element name="item"maxOccurs="unbounded">
    <xs:complexType>
     <xs:sequence>
      <xs:elementname="title" type="xs:string"/>
      <xs:elementname="note" type="xs:string" minOccurs="0"/>
      <xs:elementname="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>

代码解析:

第一行是所有XML的声明无需赘述。

第二行为此XMLSchema本身就是一个XML)定义了一个命名空间。

从第四行开始才是对原XML的一些要求:

首先定义了根元素为shiporder(行4),其次因为shiporder元素有一个属性,其中包含其他的元素所以其为复合类型(行5)。然后通过sequence元素按照顺序包围其子元素(行10---15),描述元素的名称以及元素的类型(行11----14),如果需要描述元素的限制条件(行22)。描述根元素的属性,由于是必选属性所以选择required关键字,需要注意的是这个属性必须放在最后(行29

通过Schema验证XML的代码和前面文章中的DTD验证大同小异,代码如下:

package ValidateXml;
 
import java.io.File;
import java.io.IOException;
 
import javax.xml.XMLConstants;
import javax.xml.transform.stream.StreamSource;
import javax.xml.validation.Schema;
import javax.xml.validation.SchemaFactory;
import javax.xml.validation.Validator;
 
import org.xml.sax.ErrorHandler;
import org.xml.sax.SAXException;
 
importcom.sun.org.apache.xml.internal.utils.DefaultErrorHandler;
 
public class XmlValidator
{
    private String xsdFilePath;
 
    public XmlValidator(String xsdFilePath)
    {
        this.xsdFilePath =xsdFilePath;
    }
 
    public String validata(String xmlFilePath,ErrorHandler errorHandler)
    {
        String msg = null;
        SchemaFactoryfactory = SchemaFactory.newInstance(XMLConstants.W3C_XML_SCHEMA_NS_URI);
        try
        {
           Schema schema = factory.newSchema(new File(xsdFilePath));
           Validator validator = schema.newValidator();
           validator.setErrorHandler(errorHandler);
           validator.validate(new StreamSource(new File(xmlFilePath)));
        }
        catch (SAXExceptione)
        {
           msg = e.getMessage();
           e.printStackTrace();
        }
        catch (IOExceptione)
        {
           msg = e.getMessage();
           e.printStackTrace();
        }
        return msg;
    }
 
    public static void main(String[] args)
    {
        String xmlFilePath ="d://test2.xml";
        String xsdFilePath ="d://shiporder.xsd";
        XmlValidator my =new XmlValidator(xsdFilePath);
        String msg =my.validata(xmlFilePath, new DefaultErrorHandler());
       System.out.println(msg == null);
    }
}
 

如果原XML文件符合Schema文件中的描述则返回true;否则抛出异常进行描述哪里不符合,并且返回false。(具体的操作可在实际工程中自行定制,这里只是进行简单的描述)


posted @ 2012-08-29 20:53  郗晓勇  阅读(227)  评论(0编辑  收藏  举报