1.sax的解析过程
为了更加形象的理解sax的解析流程,于是从官网摘录出下面的图形
image.png
从图中可以看出SaxParese解析器包装了一个saxReader阅读器,当SaxParese的parsse方法被调用时, ContentHandler, ErrorHandler, DTDHandler, EntityResolver的接口的具体的实现注册到SaxReader中,这些具体实现类中的方法会被回调,这里感觉就像观察者模式
,实现了观察者和被观察者的松度耦合,观察者可以是ErrorHandler的接口的具体实现也可以是DtdHandler的接口的实现,等到了具体的解析流程到了哪一步骤,就会自动通知调用具体的接口,又有点像模板方法
,解析流程是固定的流程,具体的实现细节有实现了接口的子类来决定。
SAXParserFactory
: 有系统属性决定创建解析器
SAXParser
: SAXParser定义了集中parser的接口,将xml数据源和具体的DefaultHandler 给解析器,就会在xml处理过程中调用具体的处理方法
SAXReader
:SAXParser包含了SAXReader,可以通过SAXParser.getXMlReader得到阅读器对象,可以对SAXReader进行接口的配置,比如配置ContentHandler的具体实现。
DefaultHandler
: ContentHandler, ErrorHandler, DTDHandler, and EntityResolver接口的空实现,你可以继承这个类,对其中的方法进行覆盖。
ContentHandler
:startDocument, endDocument, startElement, endElement 等方法在xml标签被识别时会自动调用,这个接口还定义了方法characters()和processingInstruction(),它们分别在解析器遇到XML元素或内联处理指令中的文本时调用。
ErrorHandler
: 方法error()、fatalError()和warning()在响应各种解析错误时被调用。默认错误处理程序为致命错误抛出异常,并忽略其他错误(包括验证错误)。这就是您需要了解SAX解析器的原因之一,为了确保正确的处理,您需要向解析器提供您自己的错误处理程序
DTDHandler
:定义通常不会调用的方法。在处理DTD时用于识别未解析实体的声明并对其进行操作
EntityResolver
:当解析器必须标识由URI标识的数据时,将调用resolveEntity方法。在大多数情况下,URI只是一个URL,它指定文档的位置,但在某些情况下,文档可能由URN标识——web空间中唯一的公共标识符或名称。除了URL之外,还可以指定公共标识符。然后,EntityResolver可以使用公共标识符而不是URL来查找文档——例如,如果存在文档,则访问文档的本地副本。(可以用这个接口来验证xml的文档的元素是否正确,根据URL来转换为具体的xsd,dtd的文件的具体位置
dom解析的内容会给出这一块内容)
2.具体的实例
要求:先给出一个Person.xml的文件,要通过java的sax解析出该内容,并封装到People这个对象中,并打印出解析的内容
- 具体的Person.xml文件内容如下
<?xml version="1.0" encoding="UTF-8"?>
<PeopleList>
<People id="1">
<Name en='zhangsan'>张三</Name>
<Age>20</Age>
</People>
<People id="2">
<Name en='lisi'>李四</Name>
<Age>30</Age>
</People>
</PeopleList>
- 对应的People实体如下:
public class People {
private String id;
private String name;
private String englishName;
private String age;
public String getId() {
return id;
}
public void setId(String id) {
this.id = id;
}
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
public String getEnglishName() {
return englishName;
}
public void setEnglishName(String englishName) {
this.englishName = englishName;
}
public String getAge() {
return age;
}
public void setAge(String age) {
this.age = age;
}
}
- 具体的解析程序(
重点理解sax是基于事件驱动的,通过回调来实现解析的
)
import java.io.File;
import java.io.FileInputStream;
import java.util.ArrayList;
import java.util.List;
import javax.xml.parsers.SAXParser;
import javax.xml.parsers.SAXParserFactory;
import org.xml.sax.Attributes;
import org.xml.sax.SAXException;
import org.xml.sax.helpers.DefaultHandler;
/**
* sax 解析示例
*/
public class SaxXML {
public static void main(String[] args) {
File file = new File("D:\\Eclipse2018Data\\personProject\\jdk\\java-jaxp\\src\\main\\java\\com\\java\\jaxp\\sax\\Person.xml");
try {
SAXParserFactory spf = SAXParserFactory.newInstance();
SAXParser parser = spf.newSAXParser();
SaxHandler handler = new SaxHandler("People");
//给SAXParser设置xml的数据源和DefaultHandler的具体实现
parser.parse(new FileInputStream(file), handler);
List<People> peopleList = handler.getPeoples();
//打印内容
for(People people : peopleList){
System.out.println(people.getId()+"\t"+people.getName()+"\t"+people.getEnglishName()+"\t"+people.getAge());
}
} catch (Exception e) {
e.printStackTrace();
}
}
}
//SaxHandler 默认实现了DefaultHandler 接口,这个DefaultHandler接口实现了四个接口
class SaxHandler extends DefaultHandler {
private List<People> peoples = null;
private People people;
private String currentTag = null;
private String currentValue = null;
private String nodeName = null;
public List<People> getPeoples() {
return peoples;
}
public SaxHandler(String nodeName) {
this.nodeName = nodeName;
}
// 当读到一个开始标签的时候,会触发这个方法
@Override
public void startDocument() throws SAXException {
super.startDocument();
//创建一个pesples的数组对象
peoples = new ArrayList<People>();
}
//当文档解析的时候,会触发这个方法
@Override
public void endDocument() throws SAXException {
super.endDocument();
}
// 当遇到元素标签的时候,调用这个方法
@Override
public void startElement(String uri, String localName, String name,
Attributes attributes) throws SAXException {
super.startElement(uri, localName, name, attributes);
//判断是否有People这个元素,有则创建People对象
if (name.equals(nodeName)) {
people = new People();
}
//People标签的属性是否为null
if (attributes != null && people != null) {
for (int i = 0; i < attributes.getLength(); i++) {
if(attributes.getQName(i).equals("id")){
//获取People标签的属性为id的值
people.setId(attributes.getValue(i));
}
else if(attributes.getQName(i).equals("en")){
people.setEnglishName(attributes.getValue(i));
}
}
}
//给currentTag赋值
currentTag = name;
}
// 这个方法用来处理在XML文件中读到的内容
@Override
public void characters(char[] ch, int start, int length)
throws SAXException {
super.characters(ch, start, length);
if (currentTag != null && people != null) {
//得到标签体的内容
currentValue = new String(ch, start, length);
if (currentValue != null && !currentValue.trim().equals("") && !currentValue.trim().equals("\n")) {
if(currentTag.equals("Name")){
people.setName(currentValue);
}
else if(currentTag.equals("Age")){
people.setAge(currentValue);
}
}
}
currentTag = null;
currentValue = null;
}
//在遇到结束标签的时候,调用这个方法
@Override
public void endElement(String uri, String localName, String name)
throws SAXException {
super.endElement(uri, localName, name);
if (name.equals(nodeName)) {
peoples.add(people);
}
}
}
- 输出结果为:
1 张三 zhangsan 20
2 李四 lisi 30
网友评论