`
zcwfeng
  • 浏览: 106667 次
  • 性别: Icon_minigender_1
  • 来自: 吉林
社区版块
存档分类
最新评论

android 自带sax解析

 
阅读更多
public class AtomParser extends DefaultHandler {
// br节点高度,如果有连续的br节点,则存在br节点高度值,且该值项目组可通过brHeight配置具体大小
private int brHeight_;
// 判断br节点是否连续
private int brIndex_;
// 脚本文件,该内容应该在解析完页面后执行,
private Stack scriptStack_;
// 节点样式display属性列表,存储每个节点样式display的属性值。由于在节点尾需要读取对应的display属性,所以创建该堆栈
private Stack displayStack_;
// 标志控件在Br节点之后
static boolean ISAFTERBR;
// 是否已插入界面中部结构
boolean isInsertLLV_;
Activity activity_;
// 节点队列,方便添加子节点
Stack stack_;
// 节点名堆栈
Stack nodeNameStack_;
final int START_DOCUMENT = 0;
final int END_DOCUMENT = 1;
final int START_TAG = 2;
final int END_TAG = 3;
final int TEXT = 4;
// 触发的事件类型
int eventType_;
// 读取中间节点值的次数
int readTextIndex_;
// 存储节点值
StringBuffer buf_ = new StringBuffer(10);
private LPPieChart pieChart_;
private LPSelect select_;
// 解析类型,是全部解析或者局部解析
private int parseType_;
// 解析出来是整个界面结构标志
public static final int ENTIRE = 0;
// 解析出来是局部控件标志
public static final int PARTLY = 1;
// 存储整个界面的样式,且里面内容只为当前界面样式一个元素,该界面指整个手机界面
// 并非弹出框的显示的部分界面,与PARTLY相对应
private static Stack ENTIRESTACK;
// 报文是否含样式节点标记
private boolean haveStyle_;


/**
*
* @param activity
* @param type
* 解析类型 0 整个界面结构解析 1 局部控件解析
*/
public AtomParser(Activity activity, int type) {
activity_ = activity;
parseType_ = type;
}


// XML开始解析时调用此方法
public void startDocument() throws SAXException {
eventType_ = START_DOCUMENT;
stack_ = new Stack();
nodeNameStack_ = new Stack();
displayStack_ = new Stack();
scriptStack_ = new Stack();
if (parseType_ == ENTIRE) {
Component.VWIDGETARRAY = new ArrayList(2);
ENTIRESTACK = new Stack();
Component.radioList_ = null;
}
ComponentCopy.CC = null;
}


// 解析到Element的开头时调用此方法
public void startElement(String namespaceURI, String localName, String qName, Attributes atts) throws SAXException {
eventType_ = START_TAG;
// 将读取节点值次数标记复位
readTextIndex_ = 0;
nodeNameStack_.add(localName);
if (localName.equalsIgnoreCase("script")) {
Component.LUASTATE.gc(LuaState.LUA_GCCOLLECT, 0);
String src = getAttrString(atts, "src");
if (null != src) {
if (src.startsWith("/")) {
downloadLuaFromServer(src);
} else {
Component.LUASTATE.LdoString(Utils.getStringFormAsset(activity_, src));
}
}
} else if (((nodeNameStack_.indexOf("body") != -1) && (parseType_ == ENTIRE)) || (parseType_ == PARTLY)) {
if (localName.equalsIgnoreCase("style") || localName.equalsIgnoreCase("head")
|| localName.equalsIgnoreCase("content"))
return;
ComponentCopy ccCopy = new ComponentCopy();
ccCopy.setName(localName);
final int size = atts.getLength();
for (int i = 0; i < size; i++) {
// 循环读取节点中的属性,存入结构
ccCopy.addAttrs(atts.getLocalName(i), Utils.insteadOfSpecillCharacter(atts.getValue(i).trim(), false));
}


if (!stack_.isEmpty()) {
String temp = null;
if (null != ccCopy.nodeAttrsMap_ && !ccCopy.nodeAttrsMap_.isEmpty()) {
// 取当前节点的属性值,如果存在的话
temp = (String) ccCopy.nodeAttrsMap_.get("class");
}
if (null != temp && null != CssStyle.STYLEHASH) {
CssStyle cs = (CssStyle) CssStyle.STYLEHASH.get(temp.trim());
if (isInsertLLV_ && null != cs && null != cs.position_) {
// 如果已经插入llv节点,且当前节点存在positon属性,表示该节点占据的应是界面下方位置
// ,所以它不应该在llv节点内,此时应将llv节点从栈中移除。
// 暂时只支持上中下三结构的position的定位
stack_.pop();
}
}
}


String className = atts.getValue("class");
String display = null;
if (null != className) {
if (null != CssStyle.STYLEHASH) {
CssStyle cs = (CssStyle) CssStyle.STYLEHASH.get(className.trim());
if (null != cs) {
display = (String) cs.getProperty(CssStyle.DISPLAY);
}
}
}
displayStack_.add(display);
if (!localName.equalsIgnoreCase("body") && (!stack_.isEmpty())) {
// 此节点不是第一个节点,将该节点加入前面节点的子元素队列
((ComponentCopy) stack_.peek()).addChilds(ccCopy);
}
stack_.add(ccCopy);


}


}


/**
* 根据src中的url去服务器download指定的lua代码并加载到lua引擎中
*
* @param src
* eg: "/ebank/lua/ebank_request.lua"
*/
private void downloadLuaFromServer(String src) {
final String uri = Utils.getConfigStringFormAsset(activity_, "SERVER_URI").concat(src);
Utils.printOutToConsole("downloadLuaFromServer()------" + uri);
HttpManager hm = new HttpManager(activity_);
String luastr = (String) hm.sendPostRequest(uri, null, null, null);
if (luastr != null && !luastr.trim().equals("")) {
// 不要太频繁调gc.
// Component.LUASTATE.gc(LuaState.LUA_GCCOLLECT, 0);
Component.LUASTATE.LdoString(luastr);
}
}


// XML解析结束时调用此方法
public void endDocument() throws SAXException {
eventType_ = END_DOCUMENT;
activity_.runOnUiThread(new Runnable() {


@Override
public void run() {
// TODO Auto-generated method stub
// 当xml元素转为view的时候,防止view在创建过程中其他线程对view进行操作导致的异常
if (null != ComponentCopy.CC) {
xmlToView(ComponentCopy.CC, null);
if (parseType_ == ENTIRE) {
ComponentCopy.COMPONENT.mouldAndLayout();
} else {
ComponentCopy.COMPONENTPARTLY.mouldAndLayout();
}
}
if (null != scriptStack_ && scriptStack_.size() > 0) {
final int size = scriptStack_.size();
String scriptText = "";
int index;
synchronized (this) {
for (int i = 0; i < size; i++) {
scriptText = scriptStack_.get(i).toString();
index = Component.LUASTATE.LdoString(scriptText);


if (index > 0) {
Utils.printOutToConsole("Lua Text has some errors:");
Utils.printOutToConsole(Component.LUASTATE.LcheckString(-1));
}
}
}
}
// 清空该类用到的相关资源
stack_ = null;
nodeNameStack_ = null;
displayStack_ = null;
pieChart_ = null;
select_ = null;
activity_ = null;
buf_ = null;
if (null != scriptStack_)
scriptStack_.removeAllElements();
scriptStack_ = null;


}
});


}


/**
* 该方法将控件从树状结构ComponentCopy中解析出来,并将他们逐个加到上一级的childrenList_队列中
*
* @param cc
* 为控件自己
* @param component
* 为控件父控件
*/
private void xmlToView(ComponentCopy cc, Component component) {
// TODO Auto-generated method stub
try {
// 遍历cc中的所有元素,如果是样式报文,则将样式报文分解成样式序列
final String name = cc.nodeName_;
String nameType = (String) cc.getAttr("type");
if (null == nameType)
nameType = "";
// 如果cc是其他元素则查看它是不是控件
// 先将cc在控件列表ParseWidgets.WIDGETSLIST中对应的控件查找出来


Object o = ParseWidgets.initWidget(cc.nodeName_.concat("-").concat(nameType));
if (o instanceof LPWrap) {
ISAFTERBR = true;
brIndex_++;
// br节点连续,则需要计算控件前面br的累加高度和框架内控件间距,
// br高度值在Config配置文件中通过brHeight设置
if (brIndex_ > 1) {
int h = 0;
if (component instanceof LPLayout)
h = ((LPLayout) component).getVG();
brHeight_ += Utils.getBrHeight() + h;
}
return;
} else {
brIndex_ = 0;
}


if (null != o) {
Component comp = (Component) o;
// 如果元素o不为空,说明是系统控件此时要做以下几点事情:
// 1、将对应的cssstyle样式赋给该控件
// 如果当前报文没有style样式节点,且解析类型为局部解析
// 表示当前报文做的操作为局部刷新,控件样式需要对应到最近的全局报文中去
if (!haveStyle_ && parseType_ == PARTLY && null != ENTIRESTACK && !ENTIRESTACK.isEmpty())
CssStyle.STYLEHASH = (HashMap) ENTIRESTACK.get(0);
comp.setCssStyle((CssStyle) CssStyle.STYLEHASH.get(cc.nodeAttrsMap_.get("class")));
// 2、将对应的属性集合赋给该控件
comp.setProperty((HashMap) cc.getAttrs());
if (ISAFTERBR) {
// 赋值换行标记
comp.isAfterBr_ = ISAFTERBR;
ISAFTERBR = false;
}


comp.setBrHeight(brHeight_);
// br节点不连续,即使将br节点高度值清零
brHeight_ = 0;
// 所有控件的显示值存储在节点值中
comp.property_.put("text", cc.nodeValue_);
comp.initRealView(activity_, cc.nodeValue_);
comp.childrenList_ = new ArrayList<Component>(2);
comp.setTag(cc.nodeName_);
// 将控件加入控件集合
Component.VWIDGETARRAY.add(comp);
if (null != component) {
component.childrenList_.add(comp);
comp.setParent(component);
} else {
if (parseType_ == ENTIRE) {
ComponentCopy.COMPONENT = comp;
} else {
ComponentCopy.COMPONENTPARTLY = comp;
}
}


// 4、检查该控件是否存在子元素,如果是则遍历其子元素
int size = cc.getChildren().size();
for (int i = 0; i < size; i++) {
xmlToView(cc.getChild(i), comp);
}


}
} catch (Exception e) {
Utils.printException(e);
}
}


private void setClassField(Class c, String name, Object value) {
// TODO Auto-generated method stub
try {
Field field = null;
field = c.getDeclaredField(name);
field.set(field, value);
} catch (IllegalArgumentException e) {
// TODO Auto-generated catch block
Utils.printException(e);
} catch (IllegalAccessException e) {
// TODO Auto-generated catch block
Utils.printException(e);
} catch (SecurityException e) {
// TODO Auto-generated catch block
Utils.printException(e);
} catch (NoSuchFieldException e) {
// TODO Auto-generated catch block
Utils.printException(e);
}
}


// 解析到Element的结尾时调用此方法
public void endElement(String namespaceURI, String localName, String qName) throws SAXException {
eventType_ = END_TAG;
String content = "";
if (null != buf_) {
content = buf_.toString().trim();
content = Utils.insteadOfSpecillCharacter(content, false);
}
if (localName.equalsIgnoreCase("style")) {
haveStyle_ = true;
// 读取界面的样式值,并赋给stylehash变量
CssStyle.STYLEHASH = CssStyle.parseStyle(content);
// 存储全局界面的样式,该栈元素始终唯一,保存当前全界面的样式
if (parseType_ == ENTIRE)
ENTIRESTACK.add(CssStyle.STYLEHASH);
// 清空节点值
buf_ = null;
return;
} else if (localName.equalsIgnoreCase("script")) {
if (null != content || !content.equals("")) {
// Component.LUASTATE.LdoString(content);
scriptStack_.add(content);
}
// 清空节点值
buf_ = null;
return;
}
if ((nodeNameStack_.indexOf("body") != -1) && (parseType_ == ENTIRE)) {
// 将该元素赋给静态变量,以备程序调用
if (!stack_.isEmpty() && null == ComponentCopy.CC)
ComponentCopy.CC = (ComponentCopy) stack_.get(0);
ComponentCopy cc = (ComponentCopy) stack_.peek();
cc.setValue(content);
displayStack_.pop();
// 将该节点出栈,使栈顶元素为其上层节点,方便其上层节点添加新的子元素
stack_.pop();
if (null != CssStyle.STYLEHASH) {
CssStyle cs = (CssStyle) CssStyle.STYLEHASH.get(cc.nodeAttrsMap_.get("class"));
insertLLVCode(cs);
}
} else if (parseType_ == PARTLY) {
if (localName.equalsIgnoreCase("head") || localName.equalsIgnoreCase("content"))
return;
if (!stack_.isEmpty()) {
ComponentCopy cc = (ComponentCopy) stack_.peek();
cc.setValue(content);
if (null == ComponentCopy.CC)
ComponentCopy.CC = (ComponentCopy) stack_.get(0);
}


displayStack_.pop();
// 将该节点出栈,使栈顶元素为其上层节点,方便其上层节点添加新的子元素
stack_.pop();
}
nodeNameStack_.pop();
// 清空节点值
buf_ = null;
}


/**
* 插入llV节点,该节点是android界面结构需要,手动加入,在服务端提供的xml报文中不会有体现
*
* @param cs
*/
private void insertLLVCode(CssStyle cs) {
// TODO Auto-generated method stub
// 取得控件样式position对应的值,决定是否插入llv节点,该控件纯粹是为了管理界面结构,没有任何表现形式.
if (null != cs && null != cs.position_) {
// 获取控件的position样式
if (!isInsertLLV_) {
// 更改标记,表示已执行插入操作
isInsertLLV_ = true;


// 在llv节点之前插入br节点,模拟换行效果
ComponentCopy tempBr = new ComponentCopy();
tempBr.setName("br");
((ComponentCopy) stack_.peek()).addChilds(tempBr);


// 尚未插入界面中部总管理器节点,在此执行插入操作
ComponentCopy temp = new ComponentCopy();
temp.setName("llv");
((ComponentCopy) stack_.peek()).addChilds(temp);
stack_.add(temp);
}
}
}


// 取得Element的中间夹的字符串
public void characters(char ch[], int start, int length) {
if (eventType_ == END_TAG && length > 1) {
// 如果紧接着end_tag后面有需要获取出来的数据则执行
readTextIndex_ = 0;
}
try {
eventType_ = TEXT;
if (readTextIndex_ == 0) {
// 节点计数器为零表示是第一次读取该节点值。应将以前读取的值全部清空。该处执行赋空操作,如果执行delete操作数据量大的话会引起内存溢出问题。
buf_ = null;
buf_ = new StringBuffer(10);
}
// 读取节点值
if (null != buf_)
buf_.append(ch, start, length);
// 节点值计数器累加
readTextIndex_++;


} catch (Exception e) {
// TODO Auto-generated catch block
Utils.printException(e);
}
}


/**
* @param atts
* @param attrName
* @return
*/
private final String getAttrString(Attributes atts, String attrName) {
String attr = null;
try {
attr = Utils.insteadOfSpecillCharacter(atts.getValue(attrName), false);
} catch (Exception e) {
Utils.printException(e);
}
return attr;
}

}


============================================================分割===============================

/**
* 读取本地文件main.xml,根据该文件显示界面内容,并决定程序的下一步动作
*/
private void readMainXml() {
// TODO Auto-generated method stub
String mainXml = Utils.getStringFormAsset(this, "main.xml");
initLuaScript();

//解析的具体实现,handler
AtomParser apc = new AtomParser(this, AtomParser.ENTIRE);
try {
//触发解析
android.util.Xml.parse(mainXml, apc);
setContentView(ComponentCopy.COMPONENT.getLPView());
} catch (SAXException e) {
// TODO Auto-generated catch block
Utils.printException(e);
}
}

分享到:
评论

相关推荐

    android解析XML文件样例SAX方法

    Android SDK自带了SAX解析器,因此无需额外添加依赖库。接下来,我们将按照以下步骤来解析XML文件: 1. **创建XML解析器的事件处理器**: 在SAX解析过程中,我们通过实现`DefaultHandler`类来定义事件处理器。这个...

    SAX解析XML

    在Android中使用SAX解析XML: 1. 引入依赖:在项目中引入相应的解析库,如Android SDK自带的`javax.xml.parsers`包。 2. 创建XML文件:XML文件可以存储在项目的资源目录或者外部存储。 3. 编写解析逻辑:实现`...

    android实例xml解析

    - SAX解析:SAX是一种事件驱动的解析器,它逐行读取XML文件,当遇到特定的元素、属性或文本时触发回调函数。这种方式内存消耗较小,适用于处理大型XML文件。 3. Android中的PullParser解析: PullParser是Android...

    Android网络下的XML解析和生成.

    1. Android自带的XmlPullParser:这是Android系统提供的一个接口,用于实现Pull解析,它可以顺序读取XML文档并返回当前解析到的事件类型。 2. org.xmlpull.v1.XmlPullParserFactory:这个工厂类用于创建...

    Android XML和JSON解析代码

    3. **org.json库**:Android自带的JSON解析库,支持将JSON字符串转换为`JSONObject`和`JSONArray`,并提供相关的方法进行解析。 4. **Fastjson库**:阿里巴巴的高性能JSON库,适用于大量数据处理。 ### Android...

    android使用Dom,Sax,Pull,Json

    以下是对Android中四种主要解析方式——DOM、SAX、Pull和JSON的详细解释。 1. DOM(Document Object Model)解析: DOM是一种基于树形结构的XML文档模型,它将整个XML文档加载到内存中,形成一个节点树。通过这个树...

    Android 中解析xml

    SAX解析器是一种事件驱动的解析方式,它不会将整个XML文档加载到内存,而是逐行解析,当遇到特定元素时触发回调函数。这使得SAX在处理大型XML文件时更为高效。以下是如何使用SAX解析XML: 1. 创建一个实现`...

    Android高级应用源码-Android解析服务端XML.zip

    6. XML解析库:除了Android自带的解析器,还有第三方库如Simple XML、Jackson和PullParser等,这些库提供了更便捷的XML解析方式。源码中可能使用了其中的一种,以提升开发效率和代码可读性。 7. 异步处理:考虑到...

    PULL解析xml的demo

    XML解析有三种方式 1,DOM 通用性强,它会将XML文件的所有内容读取到内存中,然后使用DOM API遍历XML树、检索所需的数据;...Android自带的XML解析器,和SAX基本类似,也是事件驱动,不同的是PULL事件返回的是数值型

    应用源码之比较通用的xml解析方法.zip

    5. Android自带的XmlResourceParser 当XML资源存储在APK的res目录下时,可以使用`XmlResourceParser`来解析。它是一个轻量级的解析器,专为解析APK内的XML资源设计,效率较高。 在毕业设计或代码学习项目中,选择...

    关于UI jeson解析和xml解析

    Android SDK本身内置了两种XML解析方式:DOM解析和SAX解析。DOM解析会一次性加载整个XML文档到内存,适合小规模的XML处理;而SAX解析采用事件驱动的方式,逐行读取XML,占用内存少,适用于处理大型XML文件。除了系统...

    Android Json数据处理

    Android SDK提供了SAX解析器,通过事件回调处理XML内容。 - **DOM解析**:DOM(Document Object Model)解析器将整个XML文档加载到内存中的树形结构,方便遍历和查询。虽然适合小型XML,但对大型文档可能会消耗大量...

    比较通用的xml解析方法.zip安卓程序项目源码资源下载

    - SAX解析(Simple API for XML):事件驱动型解析,只在读取到特定元素时触发回调,内存消耗小,适合处理大型XML文件。 - Pull解析:Android提供的轻量级解析器,类似SAX,通过拉取(Pull)数据的方式解析XML,更...

    XML解析的三种方法

    本文将深入探讨三种主流的XML解析方法:SAX(Simple API for XML)、DOM(Document Object Model)以及Android自带的Pull解析器,它们各有优势,适用于不同的场景。 #### SAX解析 SAX是一种基于事件驱动的解析方式...

    安卓网站交互JSONxmlWebserviceUPnP相关-Android解析jsondome.rar

    Android中解析XML可以使用SAX(Simple API for XML)、DOM(Document Object Model)或Pull Parser。SAX是事件驱动的,适用于大文件,而DOM一次性加载整个XML文档,适合小文件。Pull Parser类似于SAX,但使用更简单...

    Android xml文件读取库

    2. SAX解析器:与DOM不同,SAX采用事件驱动模型,逐行读取XML文件,遇到元素、属性等时触发相应的回调函数。这种方式适用于处理大文件,因为它不需要一次性加载整个XML。然而,SAX解析器需要开发者手动编写回调函数...

    Android开发中解析xml文件XmlUtils工具类与用法示例

    这个工具类不是Android SDK自带的,通常是由开发者自定义实现的,例如提供的示例代码就是一个自定义的`XmlUtil`工具类。下面我们将详细探讨`XmlUtil`的用法及其内部实现。 1. **什么是`XmlUtil`** `XmlUtil`是一个...

    XML解析,初学XML解析,初学

    2. **SAX解析**:Simple API for XML,事件驱动模型,只读不存储,按需解析。当遇到XML文档的某个元素时,会触发相应的事件,如开始元素、结束元素等。这种方式节省内存,适用于大文件,但需要编写事件处理器代码。 ...

    Android手机RSS阅读器html5.zip

    解析RSS feed时,会用到XML解析库,如Android自带的SAX解析器或第三方库如TinyXML、PullParser等。 首先,应用需要连接到RSS服务器,这涉及到网络编程,包括HTTP请求的发送和响应的处理。Android提供了...

    kxml2-2.2.2

    然而,需要注意的是,KXML2并不完全符合XML Pull解析的官方规范(XPP3),因此在某些复杂场景下可能不如Android自带的`org.xmlpull.v1.XmlPullParser`稳定和全面。 总的来说,KXML2-2.2.2为Android开发者提供了一种...

Global site tag (gtag.js) - Google Analytics