常用的几种解析XML的技术!
A:DOM:在内存中构建一颗倒挂的树,通过对内存中的节点进行操作从而解析XML
缺点:由于需要根据XML文档构造倒挂的树,所以当XML文档比较大时,非常耗内存。有造成内存溢出的危险。不适合移动设备的开发.
B:SAX:基于事件驱动的方式解析XML(推模式PUSH)
C:JDOM:对DOM模型的简化,专门针对Java语言解析XML而设计的
D:DOM4J:融入了XPath语法等,是目前解析XML功能最强大的一门技术
E:PULL:基于事件驱动的方式解析XML.(拉模式(PULL))!
在xml解析过程中有一个共性:xml开始标签->xml文本内容->xml结束标签->空白文本内容->下一个xml开始标签
(1)DOM解析
//声明books集合用于存每个book对象
List<Book> books=new ArrayList<Book>();
//1.通过调用DocumentBuilderFactory的静态方法newInstance()得到DOM解析器工厂对象
DocumentBuilderFactory documentBuilderFactory=DocumentBuilderFactory.newInstance();
//2.通过DOM解析器工厂对象得到DOM解析器对象
DocumentBuilderdocumentBuilder= documentBuilderFactory.newDocumentBuilder();
//3.以流的形式指定要解析的XML文件并返回文档对象
InputStreaminputStream=Thread.currentThread().getContextClassLoader().getResourceAsStream("books.xml");
Document document=documentBuilder.parse(inputStream);
//4.通过文档对象得到根节点对应的元素对象
Elementroot=document.getDocumentElement();
//5.根据节点的名称得到节点的集合
NodeListbook_nodeList=root.getElementsByTagName("book");
//6.返回节点的个数
int len=book_nodeList.getLength();
//System.out.println("len="+len+",book_nodeList="+book_nodeList);
//7.遍历节点并获取需要的数据
for(inti=0;i<len;i++){
//根据索引获取指定的节点对象
Node node_book=book_nodeList.item(i);
//将节点向下转型成元素,为什么要转?因为只有元素对象采用根据属性名获取属性值的方法Stringvalue=getAttribute(name);
Element element_book=(Element) node_book;
//获取此节点元素的属性值
String isbn=element_book.getAttribute("isbn");
//这里获得的element_book其实是一个集合对象,根据getElementsByTagName方法获得的标签元素也是集合,但因为只有一个集合元素,所以直接item(0),然后获取其标签文本内容,getTextContent();
String name=element_book.getElementsByTagName("name").item(0).getTextContent();
String author=element_book.getElementsByTagName("author").item(0).getTextContent();
String price=element_book.getElementsByTagName("price").item(0).getTextContent();
String publish=element_book.getElementsByTagName("publish").item(0).getTextContent();
//将遍历得到的每组元素里面的小元素值通过构造函数存放到book对象中去
Book book=new Book(isbn,name,author,price,publish);
//将每个对象存放到Arraylist集合当中去
books.add(book);
(2)SAX解析
//1.通过调用SAXParserFactory工厂的静态方法newInstance()得到SAX解析器工厂对象
SAXParserFactorysaxParserFactory=SAXParserFactory.newInstance();
//2.通过SAX解析器工厂对象得到SAX解析器对象
SAXParsersaxParser=saxParserFactory.newSAXParser();
//3.指定要解析的Xml文件路径及其解析器对象
InputStreaminputStream=Thread.currentThread().getContextClassLoader().getResourceAsStream("books.xml");
saxParser.parse(inputStream, new MyHandler());
//try catch省略
4.编写处理器类中相关的方法,必须继承DefaultHandler或者实现ContentHandler接口,建议继承DefaultHandler,并重写其中的常用方法
startDocument():开始解析Xml文档时自动调用的方法
startElement():遇到开始标签时自动调用的方法
characters():遇到文本元素时自动调用的方法
endElement():遇到结束标签时自动调用的方法
endDocument():解析Xml结束后自动调用的方法
//自定义SAX解析器类必须继承DefaultHandler或者实现ContentHandler接口,建议继承DefaultHandler
private static classMyHandler extends DefaultHandler{
// 声明存储Book对象的数据源private List<Book> books;
// 声明Book对象private Book book;
//定义用来存储当前正在解析的节点的前面的标签名
private String parent;
// 当收到一个开始解析Xml的通知的时候自动调用的方法,这个方法在整个Xml解析过程中只调用一次@Override
public void startDocument()throws SAXException{
books=newArrayList<Book>(); //当开始解析xml文档时开始声明一个ArrayList()集合 用于存放每个书的信息的对象
System.out.println("=======startDocument()=========");
}
//当遇到Xml的开始标签时自动调用的方法,调用多少次取决于指定的Xml文件中有多少个开始标签//@param qName是我们解析Xml节点的标签名
@Override
public void startElement(String uri, StringlocalName, String qName,
Attributes attributes) throws SAXException {
this.parent=qName;//在遍历到开始标签时将此标签名用parent记录下来
if("book".equals(qName)){
book=new Book();//如果遍历标签时遍历到了每组数据的开始标签则new一个对象
//根据属性名获取属性值
Stringisbn=attributes.getValue("isbn");
book.setIsbn(isbn);
}
System.out.println("=====startElement(Stringuri="+uri+", String localName="+localName+", StringqName="+qName+",Attributesattributes="+attributes+")========");
}
//当遇到文本元素时自动调用的方法
@Override
public void characters(char[] ch, int start,int length)
throws SAXException {
Stringdata=new String(ch,start,length);
//当遍历到文本时它前面为开始标签名等于一下内容时,将文本内容存放到对应的对象中去
if("name".equals(parent)){
this.book.setName(data);
}elseif("author".equals(this.parent)){
this.book.setAuthor(data);
}elseif("price".equals(parent)){
this.book.setPrice(data);
}elseif("publish".equals(parent)){
this.book.setPublish(data);
}
System.out.println("=====characters(char[]ch, int start, int length).data="+data);
}
// 当前遇到Xml的结束标签时自动调用的方法,调用多少次取决于当前Xml文件中有多少个结束标签
@Override
public void endElement(String uri, StringlocalName, String qName)
throws SAXException {
//在遇到结束标签时必须将parent的值赋为null,否则会产生空白(空格,回车,换行)覆盖之前文本的情况,因为结束标签和开始标签之间的文本也会调用方法,如果没parent没置空,则此时意味着空白文本前世开始标签,则会覆盖正确的文本
this.parent=null;
if("book".equals(qName)){
this.books.add(book);//如果扫描结束标签时扫到这组的结束标签,则意味着这组结束,将这组的信息以对象的方式存放到 集合当中去
}
System.out.println("====endElement(Stringuri="+uri+", String localName="+localName+", StringqName="+qName+")=====");
}
//当收到一个当前文件解析完毕的通知后自动调用的方法,这个方法在整个Xml解析过程中也只调用一次@Override
public void endDocument() throwsSAXException {
System.out.println("books="+this.books);//结束解析后输出集合中的信息
System.out.println("======endDocument()====");
}
}
}
(3)pull解析在使用pull解析之前在java项目中需要导入第三方jar包,Android不需要。
* PULL解析:拉模式的解析方式
* 实现步骤:
* 1.得到PUll解析器工厂对象
* XmlPullParserFactoryxmlPullParserFactory=XmlPullParserFactory.newInstance();
* 2.通过工厂对象得到PULL解析器对象
* XmlPullParser xmlPullParser=xmlPullParserFactory.newPullParser();
* 3.指定要解析的Xml文件以流的形式,同时指定编码表
* InputStreaminputStream=Thread.currentThread().getContextClassLoader().getResourceAsStream("books.xml");
xmlPullParser.setInput(inputStream,"UTF-8");
4.得到当前的事件值
inteventType=xmlPullParser.getEventType();
5.循环推动事件流解析XML中的数据
while(eventType!=XmlPullParser.END_DOCUMENT){//当没遍历到文档结束之前依次遍历
switch(eventType) {
case XmlPullParser.START_DOCUMENT://当文档开始遍历时声明集合对象
books=newArrayList<Book>();
break;
case XmlPullParser.START_TAG: //遍历开始标签
StringstartTag=xmlPullParser.getName();//得到当前正在解析的标签名
if("book".equals(startTag)){
book=new Book();
String isbn=xmlPullParser.getAttributeValue(null,"isbn");
book.setIsbn(isbn);
}elseif("name".equals(startTag)){
//得到当前标签下的文本内容,此时事件流会继续向后推动
String name=xmlPullParser.nextText();
book.setName(name);
}elseif("author".equals(startTag)){
String author=xmlPullParser.nextText();
book.setAuthor(author);
}elseif("price".equals(startTag)){
String price=xmlPullParser.nextText();
book.setPrice(price);
}elseif("publish".equals(startTag)){
String publish=xmlPullParser.nextText();
book.setPublish(publish);
books.add(book);
}
System.out.println("===XmlPullParser.START_TAG中的startTag="+startTag);
break;
case XmlPullParser.END_TAG://遍历到结束标签
StringendTag=xmlPullParser.getName();//得到当前正在解析的标签名
System.out.println("===XmlPullParser.END_TAG中的endTag="+endTag);
break;
case XmlPullParser.TEXT://遍历到文本内容
System.out.println("===XmlPullParser.TEXT=====");
break;
default:
break;
}
//将事件流继续向后推动
//这句话是pull解析所必须的,因为pull解析是拉着进行的,没有这句话则会进入死循环,初学者注意
eventType=xmlPullParser.next();
}