`
mcstn61x
  • 浏览: 13451 次
最近访客 更多访客>>
社区版块
存档分类
最新评论

解析xml的几种方法,他们的原理,比较 以及JAVA源码

 
阅读更多

解析xml的几种方法,他们的原理,比较 以及JAVA源码
2010年12月16日
    解析xml的几种方法,他们的原理,比较 以及JAVA源码 收藏
  第一种方法 
  对象模型 API 定义了层次化对象模型来表示 XML 文档。换句话说,对应 XML 语法中的每个概念定义相应的类:元素、属性、实体、文档。解析器读入 XML 文档的时候,建立 XML 语法和类之间的一对一映射。比如,每遇到一个标记,就实例化一个元素类。 
  毫不奇怪,对哪种数据模型最好存在一些争议。W3C 规范化了 DOM,它的主要优点是可移植性:它是作为一种 CORBA 接口定义的,被映射到很多语言。因此如果了解了 JavaScript 中的 DOM,也就知道了 Java、C++、Perl、Python 和其他语言中的 DOM。 
  另一种数据模型是 JDOM,一种针对 Java 优化的 DOM(专用于 Java),和 Java 语言结合得更紧密,但是按照定义缺乏可移植性。 
  尽管人们可以继续商讨对 XML 语法来说哪种数据模型最好,但我认为没有多少意义,因为各种基于对象的 API 其优点和不足基本上是一样的。从好的方面来说,如果熟悉 XML 语法的话,对象模型 API 更容易理解。因为它直接从 XML 语法映射到类,很容易学习、使用和调试。 
  简单的代价是效率,至少对很多项目而言是这样。读入文档的时候,解析器根据语法结构创建对象。对很多应用程序来说,XML 语法并不是很合适: 
  * XML 语法非常罗嗦,即使文档很小,解析器也要创建很多对象。 
  * 对 XML 词汇表进行的优化通常针对的是存储和数据传输效率,而不是处理,因而应用程序可能需要对数据进行预处理,比方说,在开始真正的处理之前,先计算部分和或者合并其他来源的数据。很多情况下,在处理之前必须将数据从 XML 对象模型复制到应用程序专用的对象模型或者数据库。 
  * 因为这种对象模型是通用的,包含很多应用程序并不需要的对象之间的引用(比如,从子元素到父元素的反向引用)。这些引用进一步增加了内存消耗。 
  在桌面上处理小型文档这可能不是大问题,但是在其他环境中,比如服务器上,对象模型固有的低效率是不可接受的。 
  第二种方法 
  第二种选择是事件 API,比如 SAX。这个概念是上述对象模型方式的一种反映。只不过这种方法不根据 XML 语法定义通用的数据模型,其解析器依赖应用程序程序员建立定制的数据模型。 
  因此解析器可以做得更小,因为只需要传递最少量的信息。更重要的是,和一个型号打天下的对象模型(不管对象模型多么好)相比总的效率更高,程序员可以根据应用程序的需要定制对象模型。 
  它的优点很明显: 
  * 统计应用程序或总结信息的任何应用程序都可以从中获益,因为它们的数据模型只需计算总计而无需复制整个文档。 
  * 类似的,即使动态处理文档的应用程序(比如把文档加载到数据库中)不需处理或者只需少量处理,也可从中受益,因为根本不需要存储数据。 
  由于减少了内存需求,事件 API 可以处理任意大小的文档,包括大小超过可用内存的文档。基于同样的原因,这类 API 也非常适合多个进程并发执行和共享内存的服务器。 
  效率的代价是简单性的损失。事件 API 一向以难用著称,因为应用程序员要负责更多的操作。虽然短期看来如此,但根据我的经验,从中期和长期来看,效率上的改进足以抵消略微增加的复杂度。 
  流式 API 有两种形式:推式和拉式。从历史上看,推式方法更加流行,因为这正是 SAX 采用的模型。推式方法正在实现标准化,很快将作为 StAX 集成到 Java 平台中。 
  两者有什么区别呢?区别在于由谁控制读循环。和读取文件的任何软件一样,解析器也是围绕着读循环(读入文件的循环)创建的。 
  在推 模式(SAX)下,解析器控制循环。实际上应用程序调用解析器的时候,在文件结束之前控制权不会返回给应用程序。前面已经提到,解析器回调应用程序以建立数据模型,解析器处于控制地位。 
  在拉 模式下,应用程序控制循环。循环中应用程序负责反复调用解析器,直到文件结束。 
  推模式最适合边读入边处理 XML 文档,比如读入 RSS 提要并显示为 HTML 网页。对于使用 XML 存储数据的多数应用程序来说,"读文档"用对解析器的一次调用实现最方便。 
  拉模式更适合于处理不同 XML 词汇表的文档。这类应用程序通常需要嗅探输入(读入前几行)以根据词汇表决定调用子例程。 
  对于控制解析器的应用程序而言,一次循环是必要的,因为应用程序很容易在嗅探前面几行之后停止读入。 
  第三种方法 
  如果不提到另一种选择,即 XML 编组库形式的解析,如 Castor,本文就不完整。该方法介于对象模型和事件方法之间。 
  其思想是从 XML Schema 生成一个对象模型而不是通用模型(如 DOM),解析器生成更加针对所用词汇表的数据模型。比方说,如果词汇表处理的是发货单,那么可以预料其中会包含发送方、接收方、日期、产品类别、产品标识、单价和总价。DOM 将这些元素映射到一个一般性的元素类。编组库 为发送方、接收方、日期、产品类别、产品标识、单价、总价和文档中出现的其他元素创建专门的类。 
  从处理的是根据词汇表定制(与根据应用程序的需要定制可能相同,也可能不同)的而不是通用数据模型这方面来讲,编组库具备事件 API 的一些优点。
  -------------------------------------------------- --------------------------------------------------
  目前常用的XML的解析器主要有:SAX,DOM,Xerces
  1、SAX处理的优点非常类似于流媒体的优点。分析能够立即开始,而不是等待所有的数据被处理。而且,由于应用程序只是在读取数据时检查数据,因此不需要将数据存储在内存中。这对于大型文档来说是个巨大的优点。事实上,应用程序甚至不必解析整个文档;它可以在某个条件得到满足时停止解析。一般来说,SAX 还比它的替代者 DOM 快许多。另一方面,由于应用程序没有以任何方式存储数据,使用 SAX 来更改数据或在数据流中往后移是不可能的。
  2、DOM 以及广义的基于树的处理具有几个优点。首先,由于树在内存中是持久的,因此可以修改它以便应用程序能对数据和结构作出更改。它还可以在任何时候在树中上下导航,而不是像 SAX 那样是一次性的处理。DOM 使用起来也要简单得多。另一方面,在内存中构造这样的树涉及大量的开销。大型文件完全占用系统内存容量的情况并不鲜见。此外,创建一棵 DOM 树可能是一个缓慢的过程。
  3、选择 DOM 还是选择 SAX,这取决于下面几个因素:
  应用程序的目的:如果打算对数据作出更改并将它输出为 XML,那么在大多数情况下,DOM 是适当的选择。并不是说使用 SAX 就不能更改数据,但是该过程要复杂得多,因为您必须对数据的一份拷贝而不是对数据本身作出更改。
  数据容量: 对于大型文件,SAX 是更好的选择。数据将如何使用:如果只有数据中的少量部分会被使用,那么使用 SAX 来将该部分数据提取到应用程序中可能更好。 另一方面,如果您知道自己以后会回头引用已处理过的大量信息,那么 SAX 也许不是恰当的选择。
  对速度的需要:SAX 实现通常要比 DOM 实现更快。
  SAX 和 DOM 不是相互排斥的,记住这点很重要。您可以使用 DOM 来创建 SAX 事件流,也可以使用 SAX 来创建 DOM 树。事实上,用于创建 DOM 树的大多数解析器实际上都使用 SAX 来完成这个任务!
  4、SAX,DOM是两种对XML文档进行分析的方法(没有具体的实现,只有接口),所以不是解释器,如果光有他们,你是完成不了对xml文档的处理的。SAX的包是org.xml.sax,DOM的包是org.w3c.dom,包的名称很重要,它有助于你理解他们之间的关系。
  5、jaxp是api,他封装了sax\dom两种接口。并在sax\dom的基础之上,作了一套比较简单的api以供开发人员使用。jaxp的包是javax.xml.parsers,可以看看jaxp的源文件,它的文件中包含了对sax或者dom的引用(import)jaxp也不是具体的实现,他只是一套api。如果你仅仅有jaxp那是无法工作的,(其实jaxp只是完成对sax、dom的包装,生成了DocumentBuilderFactory\DocumentBuilder和SAXParserFactory SAXParser。也就是设计模式中的工厂模式,他的好处就是具体的对象( 解释器)建立由子类完成)
  6、xerces解释器(号称地球上最快的xml解释器)在xerces中对jaxp中定义的SAXParser SAXParserFactory DocumentBuilder DocumentBuilderFactory进行了继承(extends)对应SAXParserImpl XParserFactoryImpl DocumentBuilderImpl DocumentBuilderFactoryImpl这就是为什么你的classpath中只要有xerces.jar(其中包含了sax dom jaxp )和 xercesImpl.jar就可以的原因了.
  -------------------------------------------------- -------------------------------------------------- //xml解析的几种方式 //相关搜索: xml, 解析 //1.dom解析: package com.yzt.xml.lixin; import javax.xml.parsers.*; //import org.xml.sax.*; import java.io.*; import org.w3c.dom.*; public class DomParserDemo { static Document document; public static void main(String[] args) { //DOM解释器总类,用他创建DOM解释器 DocumentBuilderFactory factory = DocumentBuilderFactory.newInstance(); try { //创建DOM解释器 DocumentBuilder builder = factory.newDocumentBuilder(); //取得xml文件 document = builder.parse(new File("F:/XmlProject/src/com/lixin/Test.xml")); //取得结构树的根节点、 Element persons = document.getDocumentElement(); //取得标识为Persons的集合 NodeList personList = persons.getElementsByTagName("Person"); //声明属性数组 String [] personAttributes = {"id","name","genda","birthday","occupation","emai l"}; //循环访问没个person for(int i=0;i内存,推出程序 ; 终止当前正在运行的 Java 虚拟机。 } //XML文档节点开始事件 /**startElement(String namepaceURI,String IName,String qName,Attributes attrs)接收元素开始的通知。 * * IName 包含前缀名的元素名字 * qName 不包含前缀名的元素名字 * attrs 元素的属性名字 * */ public void startElement(String namepaceURI,String IName,String qName,Attributes attrs){ try { indentLevel++; newLine(); String eName = IName; //取得元素的名称 if("".equals(eName)){ eName = qName; printOut(""); } } catch (Exception ex) { ex.printStackTrace(); } } //读入元素之间数据的方法 ;;;接收元素中字符数据的通知。 public void characters(char buf[],int offset,int len){ try { /** * String(char[] value, int offset, int count) * 分配一个新的 String,它包含来自该字符数组参数的一个子数组的字符。 * */ String s = new String(buf,offset,len); if(!s.trim().equals("")){ printOut(" "+s+" "); } } catch (Exception ex) { ex.printStackTrace(); } } //xml文档节点的结束事件 public void endElement(String namespaceURI,String sName,String qName){ try { if(qName.equals("")|qName.equals("")){ newLine(); } printOut(""); indentLevel--; } catch (Exception ex) { ex.printStackTrace(); } } //显示xml文档内容的方法 private void printOut(String s){ try { out.write(s); out.flush(); } catch (Exception ex) { ex.printStackTrace(); } } //显示新的一行的方法 public void newLine(){ //System.getProperty("line.separator");获得指定键指示的系统属性。 line 有各种控件 String lineEnd = System.getProperty("line.separator"); try { out.write(lineEnd); for(int i=0;iAPI 相比,使用 dom4j 所包含的解析器的好处是 dom4j 拥有本地的 XPath 支持。 *DOM 解析器不支持使用 XPath 选择节点。 **/ public dom4j(){ } //创建自己的xml public int createXMLFile(String filename){ int returnValue=0; Document document=DocumentHelper.createDocument(); Element booksElement=document.addElement("books"); booksElement.addComment("作者:yzt2008812"); Element bookElement=booksElement.addElement("book"); bookElement.addAttribute("show", "YES"); Element titleElement=bookElement.addElement("title"); titleElement.setText("Dom4j实例应用"); bookElement=booksElement.addElement("book"); bookElement.addAttribute("show", "yes"); titleElement.setText("Lucene学习指南"); bookElement=booksElement.addElement("book"); bookElement.addAttribute("show", "no"); titleElement=bookElement.addElement("title"); titleElement.setText("spring全攻略"); Element ownerElement=booksElement.addElement("owner"); ownerElement.setText("我的测试xml"); try{ XMLWriter writer=new XMLWriter(new FileWriter(new File(filename))); writer.write(document); writer.close(); returnValue=1; }catch(Exception ex){ ex.printStackTrace(); } return returnValue; } //格式化xml文档,并解决中文问题 public int formatXMLFile(String filename){ int returnValue=0; try{ SAXReader saxReader =new SAXReader(); Document document=saxReader.read(new File(filename)); XMLWriter output=null; OutputFormat format=OutputFormat.createPrettyPrint(); format.setEncoding("GBK"); output.write(document);; output.close(); returnValue=1; }catch(Exception ex){ ex.printStackTrace(); } return returnValue; } //修改并另存为xml public int change_XMLFile(String filename,String newfilename){ int returnValue=0; try{ SAXReader saxReader=new SAXReader(); Document document=saxReader.read(new File(filename)); /* 修改内容之一: 如果book节点中show参数的内容为yes,则修改成no * * 先用xpath查找对象 * * 注意:selectNodes()参数的格式: * 节点名[@属性名='属性值'],如:book[@url='dom4j.com'] * 如果有多个节点,用"/"分开,如:book[@url='dom4j.com']/title[@id='123'] **/ List list=document.selectNodes("books/book/@show"); Iterator iter=list.iterator(); while(iter.hasNext()){ Attribute attribute=(Attribute)iter.next(); if(attribute.getValue().equals("YES")){ attribute.setValue("Noooooo"); } } }catch(Exception ex){ ex.printStackTrace(); } return returnValue; } //main方法执行操作 public static void main(String []args){ dom4j temp=new dom4j(); System.out.println(temp.createXMLFile("c:/catalog/ yzt.xml")); System.out.println(temp.change_XMLFile("c:/catalog /yzt.xml","c:/catalog/yzt22.xml")); } } /jdom解析修改xml(修改部分还是有点问题!): package com.yzt.xml; import java.io.IOException; import org.jdom.Document; import org.jdom.Element; import org.jdom.input.SAXBuilder; import org.jdom.output.Format; import org.jdom.output.XMLOutputter; import java.io.*; import java.io.FileWriter; import org.jdom.input.*; import org.jdom.output.*; import java.util.List; import org.jdom.*; public class jdom { private Element customer,name,age,sex,address,street,city,district ; //构造方法生成xml public jdom(){ customer=new Element("customer"); Document document =new Document(customer); name=new Element("name"); age=new Element("age"); sex=new Element("sex"); address=new Element("address"); street=new Element("street"); city=new Element("city"); district=new Element("district"); name.addContent("张三"); age.addContent("25"); sex.addContent("湖北"); city.addContent("北京"); street.addContent("上地三街"); district.addContent("海淀区"); address.addContent(street); address.addContent(city); address.addContent(district); customer.addContent(name); customer.addContent(age); customer.addContent(sex); customer.addContent(address); XMLOutputter fmt=new XMLOutputter(); try{ FileWriter writer=new FileWriter("c:/catalog/customer.xml"); Format f=Format.getPrettyFormat(); f.setEncoding("GB2312"); fmt.output(document, writer); }catch(IOException e){ e.printStackTrace(); } jdom_change_xml(); } //修改xml public int jdom_change_xml(){ int returnValue=0; System.out.println(returnValue+"*********"); try{ SAXBuilder sab=new SAXBuilder(); Document doc=sab.build(new FileInputStream("c:/catalog/sampleA.xml")); Element root=doc.getRootElement(); List books=root.getChildren(); Element book=(Element)books.get(0); Attribute newattribute=new Attribute("QQQQ","WWWW"); book.setAttribute(newattribute); Element author=(Element)book.getChild("author"); author.setText("yztxlty"); System.out.println(author.getText().toString()+"77 77"); Element price =book.getChild("price"); price.setText(Float.toString(1000000)); String indent =" "; boolean newLines=true; XMLOutputter outp=new XMLOutputter(); outp.output(doc, new FileOutputStream("c:/catalog/exampleB_yzt.xml")); System.out.print(returnValue+"+++++++++++"); return returnValue=1; }catch(Exception ex){ ex.printStackTrace(); //System.out.print(returnValue+"999999999"); } System.out.print(returnValue+"^^^^^^^^^^"); return returnValue; } public static void main(String []args){ new jdom(); //System.out.print(new jdom_change_xml()); } } //用到的xml文件 请参考 附件或者文档 //from: http://javalive.5d6d.com/frame.php?frameon=yes&ref erer=http://javalive.5d6d.com/thread-257-1-1.html  
分享到:
评论

相关推荐

    JAVA上百实例源码以及开源项目源代码

    Applet钢琴模拟程序java源码 2个目标文件,提供基本的音乐编辑功能。编辑音乐软件的朋友,这款实例会对你有所帮助。 Calendar万年历 1个目标文件 EJB 模拟银行ATM流程及操作源代码 6个目标文件,EJB来模拟银行ATM...

    JAVA上百实例源码以及开源项目

    Applet钢琴模拟程序java源码 2个目标文件,提供基本的音乐编辑功能。编辑音乐软件的朋友,这款实例会对你有所帮助。 Calendar万年历 1个目标文件 EJB 模拟银行ATM流程及操作源代码 6个目标文件,EJB来模拟银行ATM...

    DWR.xml配置文件说明书(含源码)

    DWR 自动将DOM、DOM4J、JDOM和XOM转换成DOM树,前面这几种类型都仅仅返回Document,Element,Node.DWR会自动将这些转换成浏览器DOM对象.通常在启动JDOM Converter时会有一个提示信息,除非你想采用JDOMconverter否则可以...

    java开源包8

    JSEditor 是 Eclipse 下编辑 JavaScript 源码的插件,提供语法高亮以及一些通用的面向对象方法。 Java数据库连接池 BoneCP BoneCP 是一个高性能的开源java数据库连接池实现库。它的设计初衷就是为了提高数据库连接...

    java面试题

    51.5. java中有几种方法可以实现一个线程?用什么关键字修饰同步方法? stop()和suspend()方法为何不推荐使用? 25 52. 数据连接池 25 52.1. 连接池的基本原理: 25 52.2. 连接池的工作机制 25 52.3. 建立连接池 26 ...

    XML轻松学习手册--XML肯定是未来的发展趋势,不论是网页设计师还是网络程序员,都应该及时学习和了解

    在XML文档中,上述几种语句的语法都是错误的。因为: 1.所有的标记都必须要有一个相应的结束标记; 2.所有的XML标记都必须合理嵌套; 3.所有XML标记都区分大小写; 4.所有标记的属性必须用""括起来; 所以上列...

    java开源包11

    JSEditor 是 Eclipse 下编辑 JavaScript 源码的插件,提供语法高亮以及一些通用的面向对象方法。 Java数据库连接池 BoneCP BoneCP 是一个高性能的开源java数据库连接池实现库。它的设计初衷就是为了提高数据库连接...

    java开源包6

    JSEditor 是 Eclipse 下编辑 JavaScript 源码的插件,提供语法高亮以及一些通用的面向对象方法。 Java数据库连接池 BoneCP BoneCP 是一个高性能的开源java数据库连接池实现库。它的设计初衷就是为了提高数据库连接...

    java开源包9

    JSEditor 是 Eclipse 下编辑 JavaScript 源码的插件,提供语法高亮以及一些通用的面向对象方法。 Java数据库连接池 BoneCP BoneCP 是一个高性能的开源java数据库连接池实现库。它的设计初衷就是为了提高数据库连接...

    java开源包4

    JSEditor 是 Eclipse 下编辑 JavaScript 源码的插件,提供语法高亮以及一些通用的面向对象方法。 Java数据库连接池 BoneCP BoneCP 是一个高性能的开源java数据库连接池实现库。它的设计初衷就是为了提高数据库连接...

    java开源包101

    JSEditor 是 Eclipse 下编辑 JavaScript 源码的插件,提供语法高亮以及一些通用的面向对象方法。 Java数据库连接池 BoneCP BoneCP 是一个高性能的开源java数据库连接池实现库。它的设计初衷就是为了提高数据库连接...

    java开源包5

    JSEditor 是 Eclipse 下编辑 JavaScript 源码的插件,提供语法高亮以及一些通用的面向对象方法。 Java数据库连接池 BoneCP BoneCP 是一个高性能的开源java数据库连接池实现库。它的设计初衷就是为了提高数据库连接...

    java开源包10

    JSEditor 是 Eclipse 下编辑 JavaScript 源码的插件,提供语法高亮以及一些通用的面向对象方法。 Java数据库连接池 BoneCP BoneCP 是一个高性能的开源java数据库连接池实现库。它的设计初衷就是为了提高数据库连接...

    java开源包1

    JSEditor 是 Eclipse 下编辑 JavaScript 源码的插件,提供语法高亮以及一些通用的面向对象方法。 Java数据库连接池 BoneCP BoneCP 是一个高性能的开源java数据库连接池实现库。它的设计初衷就是为了提高数据库连接...

    java开源包3

    JSEditor 是 Eclipse 下编辑 JavaScript 源码的插件,提供语法高亮以及一些通用的面向对象方法。 Java数据库连接池 BoneCP BoneCP 是一个高性能的开源java数据库连接池实现库。它的设计初衷就是为了提高数据库连接...

    8583报文解析框架Simple8583.zip

    根据接触到的数据类型将数据分为如下几种类型:  CHAR(asc编码,直接使用字符串的getBytes(ENCODING)方法获取字节数组)  BINARY(二进制编码,在打包时将8位01值组装为一个字节), ...

    java开源包2

    JSEditor 是 Eclipse 下编辑 JavaScript 源码的插件,提供语法高亮以及一些通用的面向对象方法。 Java数据库连接池 BoneCP BoneCP 是一个高性能的开源java数据库连接池实现库。它的设计初衷就是为了提高数据库连接...

    java开源包7

    JSEditor 是 Eclipse 下编辑 JavaScript 源码的插件,提供语法高亮以及一些通用的面向对象方法。 Java数据库连接池 BoneCP BoneCP 是一个高性能的开源java数据库连接池实现库。它的设计初衷就是为了提高数据库连接...

    Java资源包01

    JSEditor 是 Eclipse 下编辑 JavaScript 源码的插件,提供语法高亮以及一些通用的面向对象方法。 Java数据库连接池 BoneCP BoneCP 是一个高性能的开源java数据库连接池实现库。它的设计初衷就是为了提高数据库连接...

Global site tag (gtag.js) - Google Analytics