==================
闲扯的话================
对于现在越来越轻量级,越来越讲究速度和接近用户的应用来说,xml
确实有点复杂了。解析起来不仅耗内存,而且很复杂。这就好像花了几千块钱买了个MS
Office
,但是80%
的feature
都用不着,还白白的耗着CPU
和内存。
个人觉得,设置文件用XML
其实挺好,因为设置文件一般并不太大,而且要求可读性强,还有很多乱七八糟的需求,可以利用XML
的力量。昨天搞chrome
的设置,发现chrome
的设置文件也是使用的json
,读起来也是轻松愉快。
前阵子做了个程序,需要解析豆瓣API
调用返回的XML
。真想说一句。。。豆瓣你别用XML
了。。。至少,提供个json
版的API
调用吧。
(以上谨代表个人观点)
===================
正文=================
解析豆瓣返回的xml
,实在是不想用DOM
这个重量级的玩意。DOM
这个玩意,说它强大好还是说它官僚好呢。我倾向于使用SAXP
解析。但是现在面
临的一个问题是,我需要根据xml
节点的名字和属性值(一个或者多个)来决定当前的值是不是我想要的。这就麻烦一点点。第一反应是考虑xpath
。后来觉 得不如自己做一个得了,权当是按需定制一个轻量级的xpath
。
首先定义XMLSearchUnit
类,这个类的实例用来描述一个需要在XML
中搜索的值,值可以是xml
节点的值,或者是节点的属性。
package
com.deepnighttwo.resourceresolver.douban.resolver.utils;
import
java.util.HashMap;
import
java.util.Map;
import
org.xml.sax.Attributes;
/**
*
* Represent a search task. Target could
be value of a node or attribute of the
* node.
*
*
@author
mzang
*/
public
class
XMLSearchUnit {
// attribute values to be matched during search
private
Map<String, String> attributeMatchValidation =
new
HashMap<String, String>();
// if target is an attribute, then set this member to be
the attribute name.
// if it is null or empty, then means
the target is node value.
private
String expectedAttr;
// xml path, format
is: /node_name/node_name/...
private
String xmlPath;
public
XMLSearchUnit(String xmlPath) {
this
.xmlPath
= xmlPath;
}
/**
* if current node meets the search
conditions or not. Meets means the path
* is correct and the attribute value
is matched.
*
*
@param
path
*
@param
attributes
*
@return
*/
public
boolean
match(String path, Attributes attributes) {
if
(xmlPath.equals(path) ==
false
) {
return
false
;
}
for
(String key : attributeMatchValidation.keySet()) {
String exp =
attributeMatchValidation.get(key);
String compare =
attributes.getValue(key);
if
(exp.equalsIgnoreCase(compare) ==
false
) {
return
false
;
}
}
return
true
;
}
public
Map<String, String> getAttributeMatchValidation() {
return
attributeMatchValidation;
}
public
void
addAttributeValidation(String key, String value) {
attributeMatchValidation.put(key, value);
}
public
String getXmlPath() {
return
xmlPath;
}
public
void
setAttributeMatchValidation(
Map<String, String>
attributeMatchValidation) {
this
.attributeMatchValidation
= attributeMatchValidation;
}
public
String getExpectedAttr() {
return
expectedAttr;
}
/**
* if target is node value, then set
expectedAttr to null. if target is an
* attribute value, set it to be the
attribute name.
*
*
@param
expectedAttr
*/
public
void
setExpectedAttr(String expectedAttr) {
this
.expectedAttr
= expectedAttr;
}
/**
* hash code can be cached if all
properties are not be be changed.
*/
@Override
public
int
hashCode() {
final
int
prime = 31;
int
result = 1;
result = prime
* result
+
((attributeMatchValidation ==
null
) ? 0
:
attributeMatchValidation.hashCode());
result = prime * result
+ ((expectedAttr ==
null
) ? 0 : expectedAttr.hashCode());
result = prime * result +
((xmlPath ==
null
) ? 0 : xmlPath.hashCode());
return
result;
}
@Override
public
boolean
equals(Object obj) {
if
(
this
== obj)
return
true
;
if
(obj
==
null
)
return
false
;
if
(getClass() != obj.getClass())
return
false
;
XMLSearchUnit other =
(XMLSearchUnit) obj;
if
(attributeMatchValidation
==
null
) {
if
(other.attributeMatchValidation !=
null
)
return
false
;
}
else
if
(!attributeMatchValidation
.equals(other.attributeMatchValidation))
return
false
;
if
(expectedAttr ==
null
) {
if
(other.expectedAttr !=
null
)
return
false
;
}
else
if
(!expectedAttr.equals(other.expectedAttr))
return
false
;
if
(xmlPath ==
null
) {
if
(other.xmlPath !=
null
)
return
false
;
}
else
if
(!xmlPath.equals(other.xmlPath))
return
false
;
return
true
;
}
}
这个类比较简单。就是用一个hashmap
保待匹配的attribut
键值对,用一个字符串表示期待的attribute name
,用一个字符串表示期待的node path
。
然后就是如何在SAXP
里用到这个类的实例去搜索了。
package
com.deepnighttwo.resourceresolver.douban.resolver.utils;
import
java.io.InputStream;
import
java.util.ArrayList;
import
java.util.HashMap;
import
java.util.List;
import
java.util.Map;
import
javax.xml.parsers.SAXParser;
import
javax.xml.parsers.SAXParserFactory;
import
org.xml.sax.Attributes;
import
org.xml.sax.InputSource;
import
org.xml.sax.SAXException;
import
org.xml.sax.XMLReader;
import
org.xml.sax.helpers.DefaultHandler;
/**
*
* SAXP parser working with
XMLSearchUnit.
*
*
@author
mzang
*/
public
class
DoubanSearchParser
extends
DefaultHandler {
// create and initial search units
public
static
final
XMLSearchUnit DETAILS_LINK_API_PATH =
new
XMLSearchUnit(
"/feed/entry/id");
public
static
final
XMLSearchUnit DETAILS_CONTENT_PATH =
new
XMLSearchUnit(
"/entry/summary");
public
static
final
XMLSearchUnit DETAILS_TITLE_PATH =
new
XMLSearchUnit(
"/entry/title");
public
static
final
XMLSearchUnit DETAILS_CHINESE_NAME_PATH =
new
XMLSearchUnit(
"/entry/db:attribute");
public
static
final
XMLSearchUnit DETAILS_RATINGE_PATH =
new
XMLSearchUnit(
"/entry/gd:rating");
public
static
final
XMLSearchUnit
DETAILS_RATINGE_RATER_COUNT_PATH =
new
XMLSearchUnit(
"/entry/gd:rating");
public
static
final
XMLSearchUnit DETAILS_LINK_URL_PATH =
new
XMLSearchUnit(
"/feed/entry/link");
static
{
DETAILS_LINK_URL_PATH.addAttributeValidation("rel",
"alternate");
DETAILS_LINK_URL_PATH.setExpectedAttr("href");
DETAILS_CHINESE_NAME_PATH.addAttributeValidation("lang",
"zh_CN");
DETAILS_CHINESE_NAME_PATH.addAttributeValidation("name",
"aka");
DETAILS_RATINGE_PATH.setExpectedAttr("average");
DETAILS_RATINGE_RATER_COUNT_PATH.setExpectedAttr("numRaters");
}
// a map to store the XMLSearchUnit and value
private
Map<XMLSearchUnit, String> results =
new
HashMap<XMLSearchUnit, String>();
// a counter of search unit. if it is 0, then all search
unit finds a match
// value and the result of the XML
will be skipped.
private
int
count = 0;
private
StringBuilder path =
new
StringBuilder();
private
static
final
String pathSeparater = "/";
private
XMLSearchUnit[] searchUnits;
List<XMLSearchUnit> foundItems
=
new
ArrayList<XMLSearchUnit>();
/**
* constructor, accept XML input
stream, 0 or more search unit instances.
*
*
@param
input
*
@param
expectedPath
*
@return
*/
public
Map<XMLSearchUnit, String>
parseResults(InputStream input,
XMLSearchUnit...
expectedPath) {
for
(XMLSearchUnit search : expectedPath) {
results.put(search,
null
);
}
searchUnits = expectedPath;
count = expectedPath.length;
XMLReader xmlReader =
null
;
try
{
SAXParserFactory spfactory =
SAXParserFactory.newInstance();
spfactory.setValidating(
false
);
SAXParser saxParser =
spfactory.newSAXParser();
xmlReader =
saxParser.getXMLReader();
xmlReader.setContentHandler(
this
);
xmlReader.parse(
new
InputSource(input));
}
catch
(Exception e) {
System.err.println(e);
System.exit(1);
}
return
results;
}
private
void
addToPath(String addPath) {
path.append(pathSeparater).append(addPath.toLowerCase());
}
private
void
popPath() {
int
index
= path.lastIndexOf(pathSeparater);
// String removedPath = path.substring(index);
path.delete(index, path.length());
}
@Override
public
void
startElement(String uri, String localName, String qName,
Attributes attributes)
throws
SAXException {
foundItems.clear();
if
(count == 0) {
return
;
}
// update path
addToPath(qName);
List<XMLSearchUnit>
foundAttrItems =
null
;
// check if current node matches search units. if it is a
node value
// search, then store it in a
member variable named foundItems because
// the value of the node is known
only when reaches the end of the
// node.but for attribute search,
it value is known here. So then are
// put in a local variable list
named foundAttrItems.
for
(XMLSearchUnit unit : searchUnits) {
if
(unit.match(path.toString(), attributes) ==
true
) {
if
(unit.getExpectedAttr() ==
null
) {
foundItems.add(unit);
}
else
{
if
(foundAttrItems ==
null
) {
foundAttrItems =
new
ArrayList<XMLSearchUnit>();
}
foundAttrItems.add(unit);
}
}
}
// if no attribute match, return.
if
(foundAttrItems ==
null
) {
return
;
}
// fill search unit value using attribute value. update
count.
for
(XMLSearchUnit attrUnit : foundAttrItems) {
String attrValue =
attributes.getValue(attrUnit.getExpectedAttr());
if
(results.get(attrUnit) ==
null
) {
count--;
}
results.put(attrUnit,
attrValue);
count--;
}
}
/**
* if current node matches, the the
node value is useful, store it.
*/
@Override
public
void
characters(
char
[] ch,
int
start,
int
length)
throws
SAXException {
if
(count == 0) {
return
;
}
if
(foundItems.size() == 0) {
return
;
}
for
(XMLSearchUnit unit : foundItems) {
String content =
new
String(ch, start, length);
if
(results.get(unit) ==
null
) {
count--;
}
results.put(unit, content);
}
}
@Override
public
void
endElement(String uri, String localName, String qName)
throws
SAXException {
foundItems.clear();
if
(count == 0) {
return
;
}
popPath();
}
}
分享到:
相关推荐
### Java解析XML——DOM详解 #### 一、DOM解析概念 **Document Object Model (DOM)**是一种平台和语言中立的接口,它允许程序和脚本动态地访问和更新文档的内容、结构和样式。DOM最初是为HTML设计的,但后来也被...
例如,对于DOM解析,可以创建`DOMParser`实例,然后使用`parse()`方法解析XML文档;对于SAX解析,可以实现`ContentHandler`接口,并注册到`SAXParser`中。同时,可以通过`XMLSchemaValidator`进行XML Schema验证。 ...
### Android中使用SAX解析XML 1. **引入库**:在Android项目中,SAX解析器已经内置在`org.xml.sax`包中,无需额外导入库。 2. **创建ContentHandler**:创建一个实现了`org.xml.sax.ContentHandler`接口的类,重写...
TinyXML库提供了一种简洁的方式来读取、修改和写入XML文档,使得开发者无需深入理解XML解析的底层细节就能处理XML数据。 TinyXML库主要包含以下组件: 1. **TiXMLDocument**:这是TinyXML的核心类,代表整个XML...
在处理XML时,我们通常会用到XML解析器,它们分为DOM(Document Object Model)解析器、SAX(Simple API for XML)解析器和StAX(Streaming API for XML)解析器。DOM解析器将整个XML文档加载到内存中,形成一个树形...
首先,我们需要通过`XMLReaderFactory`获取一个`XMLReader`实例,然后设置事件处理器(如`ContentHandler`和`ErrorHandler`),最后调用`parse()`方法解析XML文件。 2. **SAXParserFactory**:这是JAXP(Java API ...
- **适合解析简单结构的XML**:对于结构复杂、嵌套深度大的XML,Pull解析可能不如DOM或SAX解析直观。 在实际开发中,如Android的布局文件解析、配置文件读取或者从网络获取XML数据时,都可以使用Pull解析器进行处理...
在本主题"Android之PULL解析XML文件——新浪微博客户端首页效果"中,我们将深入探讨如何利用PULL解析器(PullParser)来处理XML数据,从而实现类似新浪微博客户端首页的动态效果。这种效果通常包括新闻标题、摘要、...
解析XML是将XML文档转换为程序可以理解的数据结构的关键步骤。本文将深入探讨XML解析的基本概念、常用方法以及相关的Java库——JDOM。 XML文档由一系列元素构成,每个元素都包含标签、属性和内容。解析XML的过程...
本文将深入探讨如何使用Apache的 Digester 库来解析XML文档,这是一款强大的工具,能够将XML数据映射到Java对象,简化了处理XML的过程。 Digester 是Apache Commons项目的一部分,它提供了一种规则驱动的方法来处理...
有两种主要方法来解析XML中的特殊字符: **方法一:使用实体引用** 实体引用是XML中最常见的处理特殊字符的方式。当你需要在XML文档中插入特殊字符时,可以使用对应的实体引用。比如,如果你想在文本中包含一个...
xmlparse.c文件包含了解析XML文档的主要实现代码。它通常会通过读取XML文档的字节流,逐步构建XML元素树。解析过程包括词法分析(Tokenization)、语法分析(Parsing)和语义分析(Semantic Analysis)。词法分析将...
本文将详细介绍如何使用两种流行的方法——`MiniDom`和`ElementTree`来解析XML文件。 #### 1. 通过 MiniDom 库解析 XML 文件 `MiniDom`是Python标准库中的一部分,它提供了DOM(Document Object Model)接口,允许...
本项目主要关注的是XML的创建和使用Pull解析器来解析XML,这是Android系统中处理XML数据的一种高效方法。接下来,我们将详细讨论这两个知识点。 首先,XML(Extensible Markup Language)是一种用于标记数据的语言...
下面是一个简单的使用PULL解析器解析XML并显示内容在`TextView`上的步骤: 1. 引入必要的库:在Android项目中,`XmlPullParser`是内置的,无需额外导入库。 2. 创建`XmlPullParser`实例:通常,我们可以使用`...
例如,解析XML文档通常从创建一个TiXMLDocument实例开始,然后调用LoadFile()或ReadFile()方法加载XML文件。一旦文档被加载,你可以通过元素、属性和文本对象的指针来遍历和操作XML结构。例如,你可以使用...
该文章详细介绍了在Android环境下如何使用SAX和PULL解析XML,包括代码示例和步骤说明,对于初学者来说非常有帮助。 最后,压缩包中的"Weather"文件很可能是示例的天气预报XML数据。通过实际解析这个文件,你可以更...
在Java编程环境中,解析XML文件是一项常见的任务,特别是在数据处理和集成中。XML(Extensible Markup Language)是一种结构化数据格式,广泛用于存储和传输数据。本教程将介绍如何使用Java解析XML文件,并将解析...
本篇文章将深入探讨Android解析XML的三种主要方法:DOM、SAX和Pull解析器,并结合源码进行分析,帮助开发者理解它们的工作原理和适用场景。 1. DOM解析: DOM(Document Object Model)解析器将整个XML文档加载到...