在Dom4j中使用xpath解析xml
公司项目解析xml使用的是SAX(Stream API for XML)解析xml数据字典。关于SAX,Simple API for XML(简称SAX)是个循序存取XML的解析器API。SAX提供一个机制从XML文件读取资料。它是除了文档对象模型(DOM)的另外一种流行选择。
优点
SAX解析器在某些方面优于DOM风格解析器。SAX解析器的内存使用量一般远低于DOM解析器使用量。DOM解析器在任何处理开始之前,必须把整棵树放在内存,所以DOM解析器的内存使用量完全根据输入资料的大小。相对来说,SAX解析器的内存内容,是只基于XML档案的最大深度(XML树的最大深度)和单一XML项目上XML属性储存的最大资料。这两个总是比整颗解析树本身还小。
因为SAX事件驱动的本质,处理文件通常会比DOM风格的解析器快。内存存取耗时,所以DOM较大的内存
使用也是一个效能议题。
因为SAX的本质,从磁盘串流读取是可行的。无法放入内存的XML文件只可能使用SAX解析器(或另外的
串流XML解析器)来处理。
缺点
SAX事件驱动的模型对于XML解析很有用,但它确实有某些缺点。
某些种类的XML验证需要存取整份文件。例如,一个DTDIDREF 属性需要文件内有项目使用指定字串当成
DTD ID属性。要在SAX解析器内验证,必须追踪每个之前遇过的ID和IDREF属性,检查是否有任何相符。
更甚者,一个IDREF不符合ID,使用者只会在整份文件都解析完后才发现,若这种连结对于建立有效输
出是重要的,那浪费在处理整份文件的时间只能舍弃。
另外,某些XML处理仅要求存取整份文件。举例来说,XSLT及XPath需要能够任何时间存取任何解析过的
XML树。当SAX以用来建构此树时,DOM解析器在设计上已经是如此了。
使用SAX
SAXReader saxreader = new SAXReader();
Document doc = saxreader.read(xmlPath);
在公司同事写的解析xml代码:
// 1.分别产生SAXReader
SAXReader saxreader = new SAXReader();
// 3.利用Document对象对象产生根元素
Document doc = DocumentFactory.getInstance().createDocument();
DictionaryModel _dictionaryModel = new DictionaryModel();
Hashtable xmlConfig = new Hashtable();
try {
Iterator it = doc.getRootElement().elementIterator();
while (it.hasNext()) {
// 5.根元素的集合对象来获取子元素
Element element = (Element) it.next();
// 7.获取子元素节点信息
if (!element.getName().equals("field")) {
if (element.getName().equals("title"))
_dictionaryModel._title = element.getText();
if (element.getName().equals("sql"))
_dictionaryModel._sql = element.getText();
if (element.getName().equals("line"))
_dictionaryModel._line = element.getText();
if (element.getName().equals("fromTable"))
_dictionaryModel._fromTable = element.getText();
if (element.getName().equals("targetTable"))
_dictionaryModel._targetTable = element.getText();
}
}
// 获取字典内字段域集合
Iterator it1 = doc.getRootElement().elementIterator("field");
while (it1.hasNext()) {
Element element = (Element) it1.next();
if (element.getName().equals("field")) {
FieldModel model = new FieldModel();
Iterator iit = element.elementIterator();
while (iit.hasNext()) {
Element ielement = (Element) iit.next();
if (ielement.getName().equals("name"))
model._name = ielement.getText();
if (ielement.getName().equals("nameType"))
model._nameType = ielement.getText();
if (ielement.getName().equals("targetName"))
model._targetName = ielement.getText();
}
xmlConfig.put(new Integer(xmlConfig.size()), model);
}
}
像上面用Iterator遍历节点,感觉速度慢,效率不优,故想自己重新写代码解析xml。
在使用Dom4j解析xml文档时,我们很希望有一种类似正则表达式的东西来规范查询条件,而xpath正是这
样一种很便利的规则吧.
数据字典:
< ?xml version="1.0" encoding="gb2312"?>
select V_STORES_LIST.* from V_stores_list
where CANUSEQTY>0 AND ??? order by whname
20
V_STORES_LIST
BO_PC_MTRREPLACE
MTRNAME
物资名称
文本
< ![CDATA[like]]>
MTRNAME
单行
< ![CDATA[]]>
RESERVENO
储位号
文本
< ![CDATA[like]]>
RESERVENO
单行
< ![CDATA[]]>
1.获取没有子节点的节点值:
public String getNodeValue(String xpath) {
List list = doc.selectNodes(xpath);
if (list.size() == 0) {
return null;
} else
return ((Element) list.get(0)).getText();
}
eg:String sql = getNodeValue(“/dictionary/sql”)
2.解析有子节点的节点值:
List list = doc.selectNodes("/dictionary/condition");
Iterator it1 = list.iterator();
while (it1.hasNext()) {
Element elt = (Element) it1.next();
String name = getNodeValue(elt, "./fieldName");
String fieldType = getNodeValue(elt, "./fieldType");
String compareType = getNodeValue(elt, "./compareType");
。。。。。。。。
}
注意看其中的xpath的写法,正是因为有了xpath,我们才能如此简单灵活的对xml进行操作.
刚刚使用xpath的时候可能会报一个错误:Exception in thread “main” java.lang.NoClassDefFoundError: org/jaxen/JaxenException
这时我们应该往CLASSPATH导入一个jar包,叫jaxen-1.1.1.jar,可从网上下载.
关于xpath的介绍:
表达式 描述
节点名 选择所有该名称的节点集
/ 选择根节点
// 选择当前节点下的所有节点
. 选择当前节点
.. 选择父节点
@ 选择属性
示例
表达式 描述
dictionary 选择所有dictionary子节点
/dictionary 选择根节点dictionary
dictionary/condition 在dictionary的子节点中选择所有名为condition的节点
//condition 选择xml文档中所有名为condition的节点
dictionary//condition 选择节点dictionary下的所有名为condition为节点
//@lang 选择所有名为lang的属性
断言
在方括号中[],用来更进一步定位选择的元素
表达式 描述
/dictionary/condition[1] 选择根元素dictionary的condition子元素中的第一个
注意: IE5以上浏览器中第一个元素是0
/dictionary/condition[last()] 选择根元素dictionary的condition子元素中的最后一个
/dictionary/condition[last()-1] 选择根元素dictionary的condition子元素中的最后第二个
/dictionary/condition[position()<3] 选择根元素dictionary的condition子元素中的前两个
//title[@lang] 选择所有拥有属性lang的titile元素
//title[@lang='eng'] 选择所有属性值lang为eng的title元素
/dictionary/condition[price>35.00] 选择根元素dictionary的condition子元素中那些拥有price子元素且值大于35的
/dictionary/condition[price>35.00]/title 选择根元素dictionary的condition子元素中那些拥有price子元素且值大于35的title子元素
选择位置的节点
通配符 描述
* 匹配所有元素
@* 匹配所有属性节点
node() 匹配任何类型的节点
示例
表达式 描述
/dictionary/* 选择根元素dictionary的下的所有子元素
//* 选择文档中所有元素
//title[@*] 选择所有拥有属性的title元素
使用操作符“|”组合选择符合多个path的表达式