JAVA中4种解析XML文件的方法
xml是一种通用的数据交换格式,它的平台无关性、语言无关性、系统无关性、给数据集成与交互带来了极大的方便。xml在不同的语言环境中解析方式都是一样的,只不过实现的语法不同而已。
xml的解析方式分为四种:
1、dom解析;
2、sax解析;
3、jdom解析;
4、dom4j解析。
其中前两种属于基础方法,是官方提供的平台无关的解析方式;后两种属于扩展方法,它们是在基础的方法上扩展出来的,只适用于java平台。
针对以下xml文件,会对四种方式进行详细描述:
<?xml version="1.0" encoding="utf-8"?> <bookstore> <book id="1"> <name>冰与火之歌</name> <author>乔治马丁</author> <year>2014</year> <price>89</price> </book> <book id="2"> <name>安徒生童话</name> <year>2004</year> <price>77</price> <language>english</language> </book> </bookstore> xml
一、dom解析
dom的全称是document object model,也即文档对象模型。在应用程序中,基于dom的xml分析器将一个xml文档转换成一个对象模型的集合(通常称dom树),应用程序正是通过对这个对象模型的操作,来实现对xml文档数据的操作。通过dom接口,应用程序可以在任何时候访问xml文档中的任何一部分数据,因此,这种利用dom接口的机制也被称作随机访问机制。
dom接口提供了一种通过分层对象模型来访问xml文档信息的方式,这些分层对象模型依据xml的文档结构形成了一棵节点树。无论xml文档中所描述的是什么类型的信息,即便是制表数据、项目列表或一个文档,利用dom所生成的模型都是节点树的形式。也就是说,dom强制使用树模型来访问xml文档中的信息。由于xml本质上就是一种分层结构,所以这种描述方法是相当有效的。
dom树所提供的随机访问方式给应用程序的开发带来了很大的灵活性,它可以任意地控制整个xml文档中的内容。然而,由于dom分析器把整个xml文档转化成dom树放在了内存中,因此,当文档比较大或者结构比较复杂时,对内存的需求就比较高。而且,对于结构复杂的树的遍历也是一项耗时的操作。所以,dom分析器对机器性能的要求比较高,实现效率不十分理想。不过,由于dom分析器所采用的树结构的思想与xml文档的结构相吻合,同时鉴于随机访问所带来的方便,因此,dom分析器还是有很广泛的使用价值的。
优点:
1、形成了树结构,有助于更好的理解、掌握,且代码容易编写。
2、解析过程中,树结构保存在内存中,方便修改。
缺点:
1、由于文件是一次性读取,所以对内存的耗费比较大。
2、如果xml文件比较大,容易影响解析性能且可能会造成内存溢出。
以下是解析代码:
public class domtest { public static void main(string[] args) { //创建一个documentbuilderfactory的对象 documentbuilderfactory dbf = documentbuilderfactory.newinstance(); //创建一个documentbuilder的对象 try { //创建documentbuilder对象 documentbuilder db = dbf.newdocumentbuilder(); //通过documentbuilder对象的parser方法加载books.xml文件到当前项目下 document document = db.parse("books.xml"); //获取所有book节点的集合 nodelist booklist = document.getelementsbytagname("book"); //通过nodelist的getlength()方法可以获取booklist的长度 system.out.println("一共有" + booklist.getlength() + "本书"); //遍历每一个book节点 for (int i = 0; i < booklist.getlength(); i++) { system.out.println("=================下面开始遍历第" + (i + 1) + "本书的内容================="); //通过 item(i)方法 获取一个book节点,nodelist的索引值从0开始 node book = booklist.item(i); //获取book节点的所有属性集合 namednodemap attrs = book.getattributes(); system.out.println("第 " + (i + 1) + "本书共有" + attrs.getlength() + "个属性"); //遍历book的属性 for (int j = 0; j < attrs.getlength(); j++) { //通过item(index)方法获取book节点的某一个属性 node attr = attrs.item(j); //获取属性名 system.out.print("属性名:" + attr.getnodename()); //获取属性值 system.out.println("--属性值" + attr.getnodevalue()); } //解析book节点的子节点 nodelist childnodes = book.getchildnodes(); //遍历childnodes获取每个节点的节点名和节点值 system.out.println("第" + (i+1) + "本书共有" + childnodes.getlength() + "个子节点"); for (int k = 0; k < childnodes.getlength(); k++) { //区分出text类型的node以及element类型的node if (childnodes.item(k).getnodetype() == node.element_node) { //获取了element类型节点的节点名 system.out.print("第" + (k + 1) + "个节点的节点名:" + childnodes.item(k).getnodename()); //获取了element类型节点的节点值 system.out.println("--节点值是:" + childnodes.item(k).getfirstchild().getnodevalue()); //system.out.println("--节点值是:" + childnodes.item(k).gettextcontent()); } } system.out.println("======================结束遍历第" + (i + 1) + "本书的内容================="); } } catch (parserconfigurationexception e) { e.printstacktrace(); } catch (saxexception e) { e.printstacktrace(); } catch (ioexception e) { e.printstacktrace(); } } }
二、sax解析
sax的全称是simple apis for xml,也即xml简单应用程序接口。与dom不同,sax提供的访问模式是一种顺序模式,这是一种快速读写xml数据的方式。当使用sax分析器对xml文档进行分析时,会触发一系列事件,并激活相应的事件处理函数,应用程序通过这些事件处理函数实现对xml文档的访问,因而sax接口也被称作事件驱动接口。
优点:
1、采用事件驱动模式,对内存耗费比较小。
2、适用于只处理xml文件中的数据时。
缺点:
1、编码比较麻烦。
2、很难同时访问xml文件中的多处不同数据。
以下是解析代码:
public class saxtest { /** * @param args */ public static void main(string[] args) { //锟斤拷取一锟斤拷saxparserfactory锟斤拷实锟斤拷 saxparserfactory factory = saxparserfactory.newinstance(); //通锟斤拷factory锟斤拷取saxparser实锟斤拷 try { saxparser parser = factory.newsaxparser(); //锟斤拷锟斤拷saxparserhandler锟斤拷锟斤拷 saxparserhandler handler = new saxparserhandler(); parser.parse("books.xml", handler); system.out.println("~!~!~!共有" + handler.getbooklist().size() + "本书"); for (book book : handler.getbooklist()) { system.out.println(book.getid()); system.out.println(book.getname()); system.out.println(book.getauthor()); system.out.println(book.getyear()); system.out.println(book.getprice()); system.out.println(book.getlanguage()); system.out.println("----finish----"); } } catch (parserconfigurationexception e) { // todo auto-generated catch block e.printstacktrace(); } catch (saxexception e) { // todo auto-generated catch block e.printstacktrace(); } catch (ioexception e) { // todo auto-generated catch block e.printstacktrace(); } } } public class saxparserhandler extends defaulthandler { string value = null; book book = null; private arraylist<book> booklist = new arraylist<book>(); public arraylist<book> getbooklist() { return booklist; } int bookindex = 0; /** * 用来标识解析开始 */ @override public void startdocument() throws saxexception { // todo auto-generated method stub super.startdocument(); system.out.println("sax解析开始"); } /** * 用来标识解析结束 */ @override public void enddocument() throws saxexception { // todo auto-generated method stub super.enddocument(); system.out.println("sax解析结束"); } /** * 解析xml元素 */ @override public void startelement(string uri, string localname, string qname, attributes attributes) throws saxexception { //调用defaulthandler类的startelement方法 super.startelement(uri, localname, qname, attributes); if (qname.equals("book")) { bookindex++; //创建一个book对象 book = new book(); //开始解析book元素的属性 system.out.println("======================开始遍历某一本书的内容================="); //不知道book元素下属性的名称以及个数,如何获取属性名以及属性值 int num = attributes.getlength(); for(int i = 0; i < num; i++){ system.out.print("book元素的第" + (i + 1) + "个属性名是:" + attributes.getqname(i)); system.out.println("---属性值是:" + attributes.getvalue(i)); if (attributes.getqname(i).equals("id")) { book.setid(attributes.getvalue(i)); } } } else if (!qname.equals("name") && !qname.equals("bookstore")) { system.out.print("节点名是:" + qname + "---"); } } @override public void endelement(string uri, string localname, string qname) throws saxexception { //调用defaulthandler类的endelement方法 super.endelement(uri, localname, qname); //判断是否针对一本书已经遍历结束 if (qname.equals("book")) { booklist.add(book); book = null; system.out.println("======================结束遍历某一本书的内容================="); } else if (qname.equals("name")) { book.setname(value); } else if (qname.equals("author")) { book.setauthor(value); } else if (qname.equals("year")) { book.setyear(value); } else if (qname.equals("price")) { book.setprice(value); } else if (qname.equals("language")) { book.setlanguage(value); } } @override public void characters(char[] ch, int start, int length) throws saxexception { // todo auto-generated method stub super.characters(ch, start, length); value = new string(ch, start, length); if (!value.trim().equals("")) { system.out.println("节点值是:" + value); } } }
三、jdom解析
特征:
1、仅使用具体类,而不使用接口。
2、api大量使用了collections类。
以下是解析代码:
public class jdomtest { private static arraylist<book> bookslist = new arraylist<book>(); /** * @param args */ public static void main(string[] args) { // 进行对books.xml文件的jdom解析 // 准备工作 // 1.创建一个saxbuilder的对象 saxbuilder saxbuilder = new saxbuilder(); inputstream in; try { // 2.创建一个输入流,将xml文件加载到输入流中 in = new fileinputstream("src/res/books.xml"); inputstreamreader isr = new inputstreamreader(in, "utf-8"); // 3.通过saxbuilder的build方法,将输入流加载到saxbuilder中 document document = saxbuilder.build(isr); // 4.通过document对象获取xml文件的根节点 element rootelement = document.getrootelement(); // 5.获取根节点下的子节点的list集合 list<element> booklist = rootelement.getchildren(); // 继续进行解析 for (element book : booklist) { book bookentity = new book(); system.out.println("======开始解析第" + (booklist.indexof(book) + 1) + "书======"); // 解析book的属性集合 list<attribute> attrlist = book.getattributes(); // //知道节点下属性名称时,获取节点值 // book.getattributevalue("id"); // 遍历attrlist(针对不清楚book节点下属性的名字及数量) for (attribute attr : attrlist) { // 获取属性名 string attrname = attr.getname(); // 获取属性值 string attrvalue = attr.getvalue(); system.out.println("属性名:" + attrname + "----属性值:" + attrvalue); if (attrname.equals("id")) { bookentity.setid(attrvalue); } } // 对book节点的子节点的节点名以及节点值的遍历 list<element> bookchilds = book.getchildren(); for (element child : bookchilds) { system.out.println("节点名:" + child.getname() + "----节点值:" + child.getvalue()); if (child.getname().equals("name")) { bookentity.setname(child.getvalue()); } else if (child.getname().equals("author")) { bookentity.setauthor(child.getvalue()); } else if (child.getname().equals("year")) { bookentity.setyear(child.getvalue()); } else if (child.getname().equals("price")) { bookentity.setprice(child.getvalue()); } else if (child.getname().equals("language")) { bookentity.setlanguage(child.getvalue()); } } system.out.println("======结束解析第" + (booklist.indexof(book) + 1) + "书======"); bookslist.add(bookentity); bookentity = null; system.out.println(bookslist.size()); system.out.println(bookslist.get(0).getid()); system.out.println(bookslist.get(0).getname()); } } catch (filenotfoundexception e) { e.printstacktrace(); } catch (jdomexception e) { e.printstacktrace(); } catch (ioexception e) { e.printstacktrace(); } } }
四、dom4j解析
特征:
1、jdom的一种智能分支,它合并了许多超出基本xml文档表示的功能。
2、它使用接口和抽象基本类方法。
3、具有性能优异、灵活性好、功能强大和极端易用的特点。
4、是一个开放源码的文件
以下是解析代码:
public class dom4jtest { private static arraylist<book> booklist = new arraylist<book>(); /** * @param args */ public static void main(string[] args) { // 解析books.xml文件 // 创建saxreader的对象reader saxreader reader = new saxreader(); try { // 通过reader对象的read方法加载books.xml文件,获取docuemnt对象。 document document = reader.read(new file("src/res/books.xml")); // 通过document对象获取根节点bookstore element bookstore = document.getrootelement(); // 通过element对象的elementiterator方法获取迭代器 iterator it = bookstore.elementiterator(); // 遍历迭代器,获取根节点中的信息(书籍) while (it.hasnext()) { system.out.println("=====开始遍历某一本书====="); element book = (element) it.next(); // 获取book的属性名以及 属性值 list<attribute> bookattrs = book.attributes(); for (attribute attr : bookattrs) { system.out.println("属性名:" + attr.getname() + "--属性值:" + attr.getvalue()); } iterator itt = book.elementiterator(); while (itt.hasnext()) { element bookchild = (element) itt.next(); system.out.println("节点名:" + bookchild.getname() + "--节点值:" + bookchild.getstringvalue()); } system.out.println("=====结束遍历某一本书====="); } } catch (documentexception e) { // todo auto-generated catch block e.printstacktrace(); } } }
final:比较总结
dom4j性能最好,连sun的jaxm也在用dom4j。目前许多开源项目中大量采用dom4j,例如大名鼎鼎的hibernate也用dom4j来读取xml配置文件。如果不考虑可移植性,那就采用dom4j。
jdom和dom在性能测试时表现不佳,在测试10m文档时内存溢出。在小文档情况下还值得考虑使用dom和jdom。虽然jdom的开发者已经说明他们期望在正式发行版前专注性能问题,但是从性能观点来看,它确实没有值得推荐之处。另外,dom仍是一个非常好的选择。dom实现广泛应用于多种编程语言。它还是许多其它与xml相关的标准的基础,因为它正式获得w3c推荐(与基于非标准的java模型相对),所以在某些类型的项目中可能也需要它(如在javascript中使用dom)。
sax表现较好,这要依赖于它特定的解析方式-事件驱动。一个sax检测即将到来的xml流,但并没有载入到内存(当然当xml流被读入时,会有部分文档暂时隐藏在内存中)。
以上就是java中4种解析xml文件的方法的详细内容,更多关于java解析xml的资料请关注其它相关文章!
推荐阅读
-
Android实现在xml文件中引用自定义View的方法分析
-
jQuery加载及解析XML文件的方法实例分析
-
java配置context.xml文件的方法图解
-
JAVA中4种解析XML文件的方法
-
Mybaits 源码解析 (六)----- 全网最详细:Select 语句的执行过程分析(上篇)(Mapper方法是如何调用到XML中的SQL的?)
-
详解在Python程序中解析并修改XML内容的方法
-
Python解析xml中dom元素的方法
-
java使用dom4j生成与解析xml文档的方法示例
-
Android编程解析XML文件的方法详解【基于XmlPullParser】
-
JAVA方法调用中的解析与分派