java中的xml解析方法主要有SAX,DOM以及pull方法,今天我尝试的是最为常见的sax方法。
首先,将xml的文件中的主要元素总结为一个类(我的类为AcctDetailRespData),xml文件的内容如下:
281066
1.0
AcctDetailResp
1
00
1
温州移动联盟卡
2984.99
0
1015
1969.99
2013-6-23 13:45:11
http://www.wzcard.com.cn/images/M00203/
01
1
20130721184120
因此,对应的类的成员变量为:String mercid, String mercnm, String address, String amount_begin, String amount_in, String amount_out, String amount_end, String bill_date, String couponid,String couponname, String pic, String targettype, String targetid, String sysdt。
/********************************************************************/
下面我们就来写为了实现SAX所要实现的接口:一般的实现方法是实现ContentHandler接口,但是因为实现ContendHandler接口重写的方法过多,所以我们可以巧妙的用继承的方法来避开这些麻烦;因为JAVA中提供了DefaultHandler类,这个类可以被SAX所识别(具体的为什么我现在也没深究,以后会奉上),我们就可以继承这个类来实现解析。
public class XMLContentHandler extends DefaultHandler
{
private static final String TAG = "XMLContentHandler";
private List adrDatas;
private AcctDetailRespData adrData;
private String preTag;
public List getAdrDatas()
{
return adrDatas;
}
@Override
public void startDocument() throws SAXException
{
adrDatas =new ArrayList();
Log.i(TAG,"startDocument...");
}
@Override
public void endDocument() throws SAXException
{
super.endDocument();
Log.i(TAG, "文档解析完毕");
}
@Override
public void startElement(String uri, String localName, String qName, Attributes attributes) throws SAXException
{
if("AcctDetailResp".equals(localName))
{
adrData = new AcctDetailRespData();
}
preTag = localName;
Log.i(TAG, "解析元素:"+localName);
}
@Override
public void endElement(String uri, String localName, String qName) throws SAXException
{
if("AcctDetailResp".equals(localName) && adrData != null )
{
adrDatas.add(adrData);
adrData = null;
}
preTag = null;
Log.i(TAG, localName + "解析元素完毕");
}
@Override
public void characters(char[] ch, int start, int length) throws SAXException
{
if(adrData != null)
{
String tempData = new String(ch, start, length);
if("MERCID".equals(preTag))
adrData.setMercid(tempData);
else if("MERCNM".equals(preTag))
adrData.setMercnm(tempData);
else if("ADDRESS".equals(preTag))
adrData.setAddress(tempData);
else if("AMOUNT_BEGIN".equals(preTag))
adrData.setAmount_begin(tempData);
else if("AMOUNT_IN".equals(preTag))
adrData.setAmount_in(tempData);
else if("AMOUNT_OUT".equals(preTag))
adrData.setAmount_out(tempData);
else if("AMOUNT_END".equals(preTag))
adrData.setAmount_end(tempData);
else if("BILL_DATE".equals(preTag))
adrData.setBill_date(tempData);
else if("COUPONID".equals(preTag))
adrData.setCouponid(tempData);
else if("COUPONNAME".equals(preTag))
adrData.setCouponname(tempData);
else if("PIC".equals(preTag))
adrData.setPic(tempData);
else if("TARGETTYPE".equals(preTag))
adrData.setTargettype(tempData);
else if("TARGETID".equals(preTag))
adrData.setTargetid(tempData);
else if("SYSDT".equals(preTag))
adrData.setSysdt(tempData);
}
Log.i(TAG, "解析内容:"+new String(ch, start,length));
}
}
实现方式很简单,遇到AcctDetailResp则创建类,遇到成员变量的名字则将其设置为变量值。
然后我们写一个类,在其中调用sax解析器,并将其包含在一个静态函数中,一边其他的地方可以自由的调用。
public class SAXAcctDetailRespDataService
{
public static List readXmlAcctDetailRespDatas(InputStream inStream) throws Exception
{
SAXParserFactory spf = SAXParserFactory.newInstance();
SAXParser saxParser = spf.newSAXParser();
XMLContentHandler handler = new XMLContentHandler();
saxParser.parse(inStream, handler);
inStream.close();
return handler.getAdrDatas();
}
}
然后就可以使用了。
需要说明的是,readXmlAcctDetailRespDatas()方法的参数是InputStream,所以我们需要将数据源转化为InputStream。我这边得到的是StringBuffer类型的,所以必须要转化:
StringBuffer buffer = new StringBuffer();
/*buffer内容的添加*/
if(buffer != null) //判断是否有内容(实际上buffer就算没有内容,也不等于null)
{
String sFromBuffer = buffer.toString();
inStream = new ByteArrayInputStream(sFromBuffer.getBytes());
}
try
{
adrAdapterDatas = SAXAcctDetailRespDataService.readXmlAcctDetailRespDatas(inStream);
}
catch (Exception e)
{
e.printStackTrace();
}
这里我得到的InputStream中只有9个AcctDetailRespData实例,但是在调试的时候发现List中有12个,后面3个为null,size的值为9,刚开始觉得有点奇怪;
;
;
;
;
;
;
;
后来想通了,数据结构中List是预先分配空间的,java机制首先在内存中开辟了够多的空间,再填入内容,在这里,不熟悉的朋友可以参考一下数据结构知识。
最后,说明一下sax的缺点:
SAX的缺点是你必须实现多个事件处理程序以便能够处理所有到来的事件,同时你还必须在应用程序代码中维护这个事件状态,因为SAX解析器不能交流元信息,如DOM的父/子支持,所以你必须跟踪解析器处在文档层次的哪个位置。如此一来,你的文档越复杂,你的应用逻辑就越复杂。虽然没有必要一次将整个文档加载到内存中,但SAX解析器仍然需要解析整个文档,这点和DOM一样。(引用自“百度百科”)