最近在做xml的解析工作,过去一直没有认真学习过xml,但是xml确实是一种很方便优秀的数据保存格式,对数据的描述非常清晰,我们是时候了解它的奥秘了。
xml是一种数据的保存格式,只关注数据的内容,不管数据的表现形式。它的跨平台性使很多软件都选择其为配置或软件数据的保存格式,而java这个跨平台的编程语言也对xml解析进行封装。
首先,jdk里面封装的xml解析方式包括dom和sax,对于dom方式,在html里面我们就已经了解得很多了,这里我不多说。而sax应该是我刚刚接触的xml特有的解析方式,他就像一个探地雷的工兵,在xml文档中探索,没经过一个元素开始、元素结束、处理指令开始、处理指令结束……都会向外报告,触发回调函数,废话不多说,直接上java代码:
1.
//构建saxfactory和saxparser,利用factory可以把验证与解析xml分离,更好地实现低耦合
SAXParserFactory saxParserFactory = SAXParserFactory.newInstance();
SAXParser noteParser = saxParserFactory.newSAXParser();
2.调用saxparser对象的parse()方法解析xml文档,调用该方法时需要传入一个defaulthandler对象,defaulthandler这个类实现了contenthandler、dtdhandler、entityresolver和errorhandler4个接口,sax用该类进行了简化事件适配器和事件监听器的关系。
//构建defaultHandler监听xml事件,svghandler继承了defaulthandler
SVGhandler notehandler=new SVGhandler();
//开始解析xml
noteParser.parse(fis, notehandler);
3.然后再svghandler里面进行xml的解析,它重写了defaulthandler几个重要的方法。
(1)characters()中可以通过new String(ch,start,length)得到当前节点的文本数据,xml里所有节点的数据都是文本数据,
/**
* 解析xml元素的文本数据
*/
@Override
public void characters(char[] ch, int start, int length)
throws SAXException {
// TODO Auto-generated method stub
super.characters(ch, start, length);
}
(2)startElement应该把它放在前面的,但是通常用它来获取节点的属性
/**
* 开始解析xml元素属性
*
* @param qName
* 元素名字通常与localName相同
* @param attributes
* 元素的属性数组
*/
@Override
public void startElement(String uri, String localName, String qName,
Attributes attributes) throws SAXException {
// 该结点属性的个数
int len = attributes.getLength();
currentTag = qName;
if(currentTag.equals("mark")){
note=new LineNotes();
}
if (len > 0) {
// System.out.println("<" + currentTag + ">Ԫ�ص���������:" );
for (int i = 0; i < len; i++) {
if (attributes.getQName(i).equals("d"))
// System.out.println(attributes.getQName(i) + "--->"
// + attributes.getValue(i));
{
String path = attributes.getValue(i);
// stringTokenizer����һ�ʵıʼ�
StringTokenizer stringTokenizer = new StringTokenizer(path);
}
}
}
}
(3)endElement结束解析xml节点触发
@Override
public void endElement(String uri, String localName, String qName)
throws SAXException {
// TODO Auto-generated method stub
super.endElement(uri, localName, qName);
}
好吧,代码就说到这里,下面对dom和sax这两种方式比较一下:
dom | sax | |
速度 | 需要一次性装入整份xml文档,并将xml文档转换为dom树,因此速度较慢 | 顺序解析xml文档,无须一次装入xml文档,因此速度很快 |
重复访问 | 将xml文档转换为dom树以后,整个解析阶段dom树常驻内存,适合重复访问,效率很好 | 顺序解析xml文档,不保存已访问的数据,因此不适合重复访问 |
内存要求 | 内存占用率大 | 不保存已访问数据,内存占用少 |
修改 | 可以读取也可以修改节点内容 | 只能读取 |
优缺点 | 可以根据dom树重复访问,但速度慢,内存占用大 | 不能重复访问,但速度快,内存占用小 |
最后,我说一下,重复访问到底有什么用?举个反例吧,sax不支持重复访问,也就是说它只顾当前节点,无法得到上下文信息,不知道当前节点的父节点和子节点的任何信息,例如下面的xml代码,你只可能知道这是一本叫疯狂java讲义的书,还有price是50,但是你不知道疯狂java讲义是50块
<book name="疯狂java讲义">
<price>50</price>
</book>
一般的xml都是上下文相关的,所以尽管sax很快,但这个缺点对于它来说是一个很大的限制。