一、kxml的前身--xmlpull
xmlpull提供了为资源有限的环境(如j2me)和j2ee应用服务器使用的xml解析API,xml pull解析允许使用stream解析的方式。
xmlpull的特点:
* 简单的接口-解析器包含一个接口、一个异常、一个建立解析器的factory;
* 无实现依赖-模仿JAXP的factory类和很容易的切换不同的XmlPull V1 API实现,而无需修改代码;
* 易用性-只有唯一的next()方法用来读取下面5类事件中的一个:
START DOCUMENT-文档起始点,这时解析器还没有准备好读取文档;
START_TAG-解析器读取到了element声明的开始标签,就是xml文件中声明element用的"<";
TEXT-解析器读取到了element的内容,如element的各种属性和value;
END_TAG-解析器读取到了element声明的结束标签,就是"/>"或者"</...>";
END_DOCUMENT-解析器读取到文档的结尾,解析工作完毕。
* 多功能性-由于提供了xml解析器的通用接口,所以允许多个实现和在特性和属性上的扩展
* 良好的性能-由于提供了通用的接口,可以说也就为使用快速的xml解析器提供了条件,但是目前最快的解析器,本人还没遇到过。:-)
* 最小化需要-设计上与j2me兼容,从而使其能工作于小型设备和建立使用微量内存的xmlPull兼容的解析器。
二、建立在良好构架上的kxml
xmlpull api提供的通用的xml内容解析功能使用方式:使用一个循环来遍历到下一个事件,并切换到一个针对这个事件的分支语句处理。但是在使用xml解析器时,一些xml element不仅包括text还有其它的element(被称为子元素或者内嵌元素)。对于这样的xml数据,解析处理被简单化到了使用xmlpull api的nextTag和nextText方法。另外,require方法也可以使用一个解析状态的参数来表示希望取得数据的event类型。以上就是kxml使用方法。
如解析下面内容的简单xml文件:
<elements>
<text>text1</text>
<text>text2</text></elements>
解析代码片断如下:
parser.nextTag();parser.require(XmlPullParser.START_TAG, null, "elements");
while(parser.nextTag() == XmlPullParser.START_TAG) { parser.require(XmlPullParser.START_TAG, null, "text");
// handle element content System.out.println("text content: "+ parser.nextText());
parser.require(XmlPullParser.END_TAG, null, "text");}parser.require(XmlPullParser.END_TAG, null, "elements");
从上面的代码看出,的确很简单明了。
三、背向kxml的原因
但是如果真正的使用kxml开发j2me程序时会发现,kxml包和其依赖的xmlpull包不仅无形中增加了程序发布时的大小,而且由于没有最好的解析器带来的负面性能损耗会随着xml文件的大小成非线性增长(还好不是指数级的)。这些成为了kxml的流行障碍。
四、轻量级的xmlReader
幸运的是kobject.org网站上提供了一个轻量级的xmlReader程序,大家可以到http://kobjects.sourceforge.net/utils/ 获取。
作为简单的xml解析器,功能上与kxml类似,但是不支持命名空间和一些传统的事件。整个jar文件大小小于5KB。
以下便是其代码:
XmlReader.java
/* Copyright (c) 2002,2003, Stefan Haustein, Oberhausen, Rhld., Germany *
* Permission is hereby granted, free of charge, to any person obtaining a copy
* of this software and associated documentation files (the "Software"), to deal
* in the Software without restriction, including without limitation the rights
* to use, copy, modify, merge, publish, distribute, sublicense, and/or
* sell copies of the Software, and to permit persons to whom the Software is
* furnished to do so, subject to the following conditions: * * The above copyright notice and this permission notice shall be included in * all copies or substantial portions of the Software. *
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
* FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS
* IN THE SOFTWARE. */package org.kobjects.xml;import java.io.*;
import java.util.*;
/** A minimalistic XML pull parser, similar to kXML, but
not supporting namespaces or legacy events. If you need
support for namespaces, or aclearcase/" target="_blank" >ccess to XML comments or
processing instructions, please use kXML(2) instead. */public class XmlReader {
/** Return value of getType before first call to next() */
public final static int START_DOCUMENT = 0;
/** Signal logical end of xml document */
public final static int END_DOCUMENT = 1;
/** Start tag was just read */ public final static int START_TAG = 2;
/** * End tag was just read
*/
public final static int END_TAG = 3;
/** Text was just read */
public final static int TEXT = 4;
final static int CDSECT = 5;
final static int ENTITY_REF = 6;
static final private String UNEXPECTED_EOF =
"Unexpected EOF";
static final private int LEGACY = 999;
// general public boolean relaxed;
private Hashtable entityMap;
private int depth;
private String[] elementStack = new String[4];
// source private Reader reader;
private char[] srcBuf =
new char[Runtime.getRuntime().freeMemory() >= 1048576
? 8192
: 128];
private int srcPos;
private int srcCount;
private boolean eof;
private int line;
private int column;
private int peek0;
private int peek1;
// txtbuffer
private char[] txtBuf = new char[128];
private int txtPos;
// Event-related
private int type;
private String text;
private boolean isWhitespace;
private String name;
private boolean degenerated;
private int attributeCount;
private String[] attributes = new String[16];
private String[] TYPES =
{
"Start Document",
"End Document",
"Start Tag",
"End Tag",
"Text" };
private final int read() throws IOException {
int r = peek0;
peek0 = peek1;
if (peek0 == -1) {
eof = true;
return r;
} else if (r == '\n' || r == '\r') {
line++;
column = 0;
if (r == '\r' && peek0 == '\n')
peek0 = 0; }
column++;
if (srcPos >= srcCount) {
srcCount = reader.read(srcBuf, 0, srcBuf.length);
if (srcCount <= 0) {
peek1 = -1;
return r;
}
srcPos = 0;
}
peek1 = srcBuf[srcPos++];
return r;
}
private final void exception(String desc)
throws IOException {
throw new IOException(
desc + " pos: " + getPositionDescription());
}
private final void push(int c) {
if (c == 0)
return;
if (txtPos == txtBuf.length) {
char[] bigger = new char[txtPos * 4 / 3 + 4];
System.arraycopy(txtBuf, 0, bigger, 0, txtPos);
txtBuf = bigger;
}
txtBuf[txtPos++] = (char) c;
} private final void read(char c) throws IOException {
if (read() != c) {
if (relaxed) {
if (c <= 32) {
skip();
read();
}
}
else {
exception("expected: '" + c + "'");
}
}
}
private final void skip() throws IOException {
while (!eof && peek0 <= ' ')
read();
}
private final String pop(int pos) {
String result = new String(txtBuf, pos, txtPos - pos);
txtPos = pos;
return result;
}
private final String readName() throws IOException {
int pos = txtPos; int c = peek0;
if ((c < 'a' || c > 'z')
&& (c < 'A' || c > 'Z')
&& c != '_'
&& c != ':'
&& !relaxed)