博客
关于我
强烈建议你试试无所不能的chatGPT,快点击我
(三) 验证XML文档
阅读量:4047 次
发布时间:2019-05-25

本文共 11536 字,大约阅读时间需要 38 分钟。

XML解析时,通过文档定义类型(DTD)或一个XML Schema定义自动检验某个文档的结构是否正确,减少处理空白字符或错误检查的工作。

例如,DTD包含一个规则<!ELEMENT font (name,size)>,表明一个font元素有两个子元素,分别是name和size。
XML Schema语言用于表示同样的约束形式如下

 

 

Schema可以表达更复杂的验证条件(比如size元素必须包含一个整数),与DTD语法不同,Schema使用XML,处理起来更方便。

1.文档定义类型(DTD Document Type Definition)
提供DTD的方式有多种
(1)直接写到XML文件中

 

more rules ]>
...

 

在该代码中使用[]来限定其界限。文档类型必须符合根元素的名字,比如上例中的root。该方法不常见,因为DTD会使XML文档变长。

(2)将DTD存储在XML文档外,并通过SYSTEM声明来实现。
可以设定一个包含DTD的URL

   

    或 

 

   

注意:如果使用的是DTD的相对URL(比如"config.dtd"),给解析器应该是一个文件或URL对象,而不是InputStream。如果必须从一个输入流来解析,需要提供实体渲染器。

(3)源于SGML的用于识别"众所周知"的DTD的机制,通过PUBLIC来定义,如果XML处理器知道如何定位带有公共标示符的DTD,则不需要URL。

 

 

如果使用的是DTD解析器,并且想要支持公共标示符,需要调用DocumentBuilder类的setEntityResolver方法来安装EntityResolver接口的某一个实现类的一个对象,该接口只有一个方法resolveEntity

 

import java.io.IOException;    import org.xml.sax.EntityResolver;    import org.xml.sax.InputSource;    import org.xml.sax.SAXException;    public class TestUsePublicDtdXML implements EntityResolver{        @Override        public InputSource resolveEntity(String publicId, String systemId)                throws SAXException, IOException {            if(publicId.equals(a know ID)){                return new InputSource(DTD data);            }            return null;        }    }
 

可以从InputStream、Reader或字符串构建输入源。
(4)ELEMENT规则用于规范某个元素可以拥有什么样的子元素。可以设定一个正则表达式,它由 元素内容规则表 所示组件构成。

元素内容的规则        规则                          含义        E*                          0或多个E        E+                          1或多个E        E?                          0或1个E        E1|E2|...|En                E1,E2...En中的一个        E1,E2,...En                 E1,随后是E2...En        #PCDATA                     文本        (#PCDATA|E1|E2|...En)       0或多个任意顺序的文本和E1,E2...En(混合式内容)        ANY                         允许任意子元素        EMPTY                       不允许有子元素
 

例1,menu元素包含0或多个item元素

 

 

例2,font是用一个name后面跟一个size来描述的,它们都包含了文本

 

 

缩写PCDTAT标识已解析的字符数据,这些数据称为“已解析的”,是因为解析器解释了该文本字符串,并正在寻找表示一个新标签起始的<字符或表示一个实体起始的&字符。

例3,元素的规范可以包含嵌套的和复杂的正则表达式,例如一个描述本书中一章的结构的规则

 

 

每章都以简介开头,后面是一个或多个小节,每一个小节有一个标题和1个或多个段落、图片、表格或说明组成。

例4,当一个元素可以包含文本时,只有两种情况,一种只包含文本。

 

    另一种元素包含任意顺序的文本和标签

 

    其他包含#PCDATA规则的类型都是非法的,比如

 

    就是非法的,需要引入另一个标签来包含文本

 

 

注意:在设计DTD时,其中所有的元素,要么包含其他元素,要么只有文本。

例5,XML标准允许解析器假设DTD都是非二义性的。比如((x,y)|(x,z))是错误的,可以修改为(x,(y|z))。((x,y)*|x?)也是错误的,但无法修改,这时并不会发出警告,而是选取第一个匹配项,这将导致拒绝一些正确的输入。
(5)ATTLIST用于描述合法元素属性的规则。通常语法是:

 

例: font元素的style属性,有4个合法属性值,默认值是plain

 

 

    size元素的unit属性可以包含任意字符串数据序列

 

 

 

属性类型    类型                含义    CDATA               任意字符串    (A1|A2|...|An)      A1、A2...An之一    NMTOKEN,NMTOKENS    1或多个名字标记    ID                  一个唯一的ID    IDREF,IDREFS        1或多个唯一ID的引用    ENTITY,ENTITIES     1或多个未经解析的实体
 

CDTAT属性值的处理与#PCDATA有差别,并且与<![CDATA[...]]>部分没有多大关系。属性值首先被规范化,解析器会处理字符和实体的引用(比如&#233;或&lt;),并且用空格来替换空白字符。

NMTOKEN(名字标记)与CDATA相似,但是大多数非字母数字字符和内部空白字符是不允许使用的,而且解析器会删除起始和结尾的空白字符。NMTOKENS是一个空白字符分隔的名字标记列表。
ID是在文档中唯一的名字标记,解析器会检查唯一性。
IDREF是对同一文档中存在的ID的引用,解析器也会对它进行检查。IDREFS是空白字符分隔的ID引用列表。
ENTITY是指一个“未经解析的外部实体”,是由SGML沿用下来的,实际应用中很少见到。DTD也可以定义实体,或者定义解析过程中被替换的缩写。

 

例: 

 

    在其他地方,文本可以包含实体的引用

 

 

    解析器用替换字符串来替换实体的引用。如果对应用程序进行国际化,只需修改实体定义中的字符串。其他实体的使用更加复杂,不常用。

属性的默认值    默认值              含义    #REQUIRED           属性是必须的    #IMPLIED            属性是可选的    A                   属性是可选的;若未指定,解析器报告的属性是A    #FIXED A            属性必须是未设定的或者是A;两者情况下,解析器报告的属性是A
 

一般情况下,推荐用元素而非属性来描述数据,比如font style应该是一个独立的元素<font><style>plain</style></font>,但对于枚举类型,属性有一个优点,解析器能确认它是否合法。
(6)配置解析器来使用DTD
1)通知文档生成工厂打开验证特性。

 

factory.setValidating(true);

 

2)指定由此工厂创建的解析器在解析 XML 文档时,必须删除元素内容中的空格

 

factory.setIgnoringElementContentWhitespace(true);
 

3)访问子元素

 

Element nameElement = (Element)children.item(0);    Element sizeElement = (Element)children.item(1);

 

  而不用

 

for(int i=0;i
 

  

该工厂生产的所有文档生成器都将根据DTD来验证输入。验证最大的好处是忽略元素内容中的空白字符。
例:

        
Helvetica
36
 

一旦设定子元素是(name,size),解析器就知道它们之间的空白字符不是文本

4)错误处理器。当解析器报告错误时,应用程序可以对该错误执行某些操作。例如,记录到日志中,把它显示给用户,或抛出一个异常以放弃解析。因此,在验证时,应该安装一个错误处理器
  错误处理器是一个实现了ErrorHandler接口的对象,这个接口有三个方法

 

public void warning(SAXParseException exception) throws SAXException;    public void error(SAXParseException exception) throws SAXException;    public void fatalError(SAXParseException exception) throws SAXException;

 

  可以通过DocumentBuilder类的setErrorHandler方法来安装错误处理器。

 

builder.setErrorHandler(handler);

 

 

 

2.XML Schema
(1)如果要在文档中引用Schema文件,需要在根元素中加上属性

 

...
 

(2)Schema定义了每个元素的类型。类型可以是简单类型、格式受限的字符串或复制类型。

一些简单类型已经被内建到了XML Schema内,包括:

 

xsd:string    xsd:int    xsd:boolean

 

注意:前缀 xsd: 来表示XML Schema定义的命名空间。也有用 XS: 作为前缀。

(3)可以自己定义简单类型simpeType
例如:定义一个枚举类型

 

 

当定义元素时,要设定它的类型:

 

 

类型约束了元素的内容,例如下面的元素将被正确验证:

 

10

 

下面的元素将会被解析器拒绝

 

default

 

(4)可以将类型组合成复制类型complexType,例如:

 

 

FontType是name,size和style的序列,在这个类型定义中,通过ref属性来引用在Schema中位于别处的定义。

也可以嵌套定义,例如:

 

 

注意:其中StyleType元素的匿名定义

(5)xsd:sequence和DTD中的连接符号等价。xsd:choice和|操作符等价。例如

 

 

这和DTD中的类型email|phone类型是等价的。

(6)如果要允许重复元素,可以使用minoccurs和maxoccurs属性,例如,与DTD类型item*的等价形式如下:

 

 

(7)如果要设定属性,可以把xsd:attribute元素加到complexType定义中:

 

...

 

这是与DTD声明等价的形式:

 

 

(8)可以把Schema的元素和类型定义封装到xsd:schema元素中:

 

...

 

(9)解析带有Schema的XML文件和解析带有DTD的文件类似,但有3点区别:

1)必须打开对命名空间的支持,即使在XML文件里不使用它:

 

factory.setNamespaceAware(true);

 

2)必须通过如下代码来准备处理Schema的工厂:

 

final String JAXP_SCHEMA_LANGUAGE = "http://java.sun.com/xml/jaxp/properties/schemaLanguage";    final String W3C_XML_SCHEMA = "http://www.w3.org/2001/XMLSchema";    factory.setAttribute(JAXP_SCHEMA_LANGUAGE, W3C_XML_SCHEMA);

 

3)解析器不会丢弃元素中的空白字符

 

 

 

3.XML解析实例

gridbag.dtd

 

 

gridbag.xsd

 

 

fontdialog.xml

 

 
text
Face:
javax.swing.JComboBox
javax.swing.JTextArea
text
Thequick brown fox jumps over the lazy dog
editable
false
lineWrap
true
border
javax.swing.border.EtchedBorder
javax.swing.JLable
text
Size:
javax.swing.JComboBox
javax.swing.JCheckBox
text
Bold
javax.swing.JCheckBox
text
Italic

 

 

ParseXMLDemo

 

package demo;import java.io.File;import java.util.ArrayList;import java.util.List;import javax.xml.parsers.DocumentBuilder;import javax.xml.parsers.DocumentBuilderFactory;import org.w3c.dom.Document;import org.w3c.dom.Element;import org.w3c.dom.NamedNodeMap;import org.w3c.dom.Node;import org.w3c.dom.NodeList;import org.w3c.dom.Text;public class ParseXMLDemo {		private static final Integer PARSE_TYPE_DOM = 1;	private static final Integer PARSE_TYPE_SAX = 2;		public static void main(String[] args) {		ParseXMLDemo demo = new ParseXMLDemo();		String fileName = System.getProperty("user.dir") + File.separator + "conf" 				+ File.separator + "xml" + File.separator + "fontdialog.xml";		Element root = demo.getRoot(fileName, PARSE_TYPE_SAX);		if(null==root){			System.out.println("文件不存在或存在其它问题");			System.exit(0);		}				demo.parseXML(root, PARSE_TYPE_DOM);	}	private void parseXML(Element element, Integer parseType) {		//该节点名称		String nodeName = element.getNodeName();		//当节点为Element时,可以通过getTagName方法获取节点名称		String tagName = element.getTagName();		//分析该节点属性		NamedNodeMap attrs = element.getAttributes();        for(int i=0;i
whitespaceList = new ArrayList
(); for(int i=0;i
0){ for(int i=whitespaceList.size()-1;i>=0;i--){ Node child = children.item(i); element.removeChild(child); } } } private Element getRoot(String fileName, Integer parseType) { try{ //得到一个DocumentBuilderFactory实例用于生成DocumentBuilder DocumentBuilderFactory factory = DocumentBuilderFactory.newInstance(); //通知文档生成工厂打开验证特性 factory.setValidating(true); //当通过Schema验证时必须加入以下代码 if(parseType == PARSE_TYPE_SAX){ //必须打开对命名空间的支持,即使在XML文件里不使用它 factory.setNamespaceAware(true); //必须通过如下代码来准备处理Schema的工厂 final String JAXP_SCHEMA_LANGUAGE = "http://java.sun.com/xml/jaxp/properties/schemaLanguage"; final String W3C_XML_SCHEMA = "http://www.w3.org/2001/XMLSchema"; factory.setAttribute(JAXP_SCHEMA_LANGUAGE, W3C_XML_SCHEMA); } //指定由此工厂创建的解析器在解析 XML 文档时,必须删除元素内容中的空格 factory.setIgnoringElementContentWhitespace(true); //从DocumentBuilderFactory中得到DocumentBuilder对象 DocumentBuilder builder = factory.newDocumentBuilder(); //读入文档 File file = new File(fileName); if(!file.exists()){ return null; } Document doc = builder.parse(new File(fileName)); return doc.getDocumentElement(); }catch(Exception e){ e.printStackTrace(); return null; } }}

转载地址:http://cayci.baihongyu.com/

你可能感兴趣的文章
leetcode面试题01.06.字符串压缩,超出时间限制,样例通过31/32
查看>>
机器学习实战、第二章KNN算法详解、AttributeError: ‘dict‘ object has no attribute ‘iteritems‘
查看>>
leetcode 535 TinyURL 的加密与解密 暴力 年轻人不讲武德—shooter7的博客
查看>>
课程设计(毕业设计)—基于机器学习KNN算法手写数字识别系统—计算机专业课程设计(毕业设计)
查看>>
leetcode1792第232场周赛第三题,以及二维数组根据某一列进行排序——优先队列
查看>>
学生网上选课管理系统的设计与实现—计算机类专业课程设计(毕业设计)
查看>>
新建动态web工程项目红叉报错,以及Could not publish server configuration for Tomcat v9.0 Server at localhost.
查看>>
机器学习SVM的车牌识别系统—计算机专业课程设计(毕业设计)
查看>>
leetcode 80. 删除有序数组中的重复项 II
查看>>
课程设计(毕业设计)—学生宿舍管理系统—计算机类专业
查看>>
毕业设计(课程设计)—SpringBoot网上订餐系统的设计与实现—计算机类专业课程设计(毕业设计)
查看>>
毕业设计(课程设计)—个人博客系统(微博)的设计与实现—计算机类专业课程设计(毕业设计)
查看>>
牛客(中兴捧月)—B-切绳子
查看>>
剑指Offer 13.机器人的运动范围——DFS和BFS
查看>>
Java中GUI编程总结—AWT中的Frame容器、panel面板、布局管理
查看>>
剑指offer12.矩阵中的路径—DFS+剪枝
查看>>
Java中GUI编程总结—事件监听、TextField监听、画笔、(鼠标、窗口、键盘)监听
查看>>
Java中GUI编程总结—Swing(窗口、面板、弹窗、标签、按钮、列表、文本框)
查看>>
Java中map容器分别根据键key和值value进行排序的总结
查看>>
剑指offer面试题16. 数值的整数次方——快速幂
查看>>