| |
简介 在1998年w3cxml1.0推荐标准发布之后,xml就开始变得很流行。sun公司就是在那时候规范java community process (jcp),同时jaxp(jsr-05)的第一版在2000早些时候发布了。这个版本得到了很多工业集团的支持,譬如(以年月次序排列)bea systems, fujitsu limited, hewlett-packard, ibm, netscape communications, oracle, and sun microsystems, inc. jaxp (全称java api for xml parsing)的可插拔性(pluggability)在开发社区里引起很大的轰动。这点也是jaxp的精华所在。开发人员可以编写自己的xml处理器,只要它符合jaxp的apis,这样底层不同的xml处理器可以任意切换而不用改应用程序的代码。 那jaxp到底是什么呢?首先 这个p有点迷惑,它代表parsing还是processing呢? 因为jaxp1.0的时候只支持解析(parsing),所以jaxp全称应该是java api for xml parsing. 但在jaxp1.1的时候,xsl-t被推荐用作xml的转换(transformation)处理。很遗憾,当时w3c xlt-t的标准规范(specification)里没有提供任何用来转换(transformation)处理的apis。因此jaxp1.1的专家组推荐了一组apis叫transformation api for xml (trax)。 从此jaxp就叫java api for xml processing. jaxp通过逐步进化,支持的东西也越来越多 不仅仅是解析xml文件(譬如在解析文档的时候根据schema校验有效性,根据预解析的schema来校验文档有效性,计算xpath 表达式等等)。 由于底层用来处理xml文档的可插拔的processor是任意编写的,只要它符合jaxp的规范,因此jaxp 是一个轻量级的处理xml文件的处理apis。(译者注:jaxp只是一个api规范而已,真正底层实现是任意的。后面会有具体介绍。) 使用jaxp来解析xml文档 jaxp支持基于对象和基于事件的两种解析方式。基于对象的解析,到目前为止只支持w3c dom解析,jaxp的专家组可能在jaxp的将来版本中会支持j-dom规范。基于事件的解析,只有sax 解析模式被支持,另一个基于事件的解析模式叫pull parsing,本来它应该是jaxp的一部分。但是对于pull parsing存在有一份不同的jsr (#173)文档,也就是大家所知道的streaming api for xml (stax) parsing,现在我们对于那个也没什么更多的可以做了。  figure 1: various mechanism of parsing xml 使用sax来解析xml文档 sax apis 是在1998年的早些时候由david megginson提出的,目标是成为基于事件驱动的xml文档解析模式的标准api(这里你可以的到一些 sax 的历史信息)。即使这样,sax仍不是w3c 的rec。但毫无疑问实际中它是行业内解析xml文档的标准。 sax 是一种基于事件的解析模式,是push-parsing原理,解析文档的时候,当遇到<opening> 标签, </closing>标签 或字符等,sax 都会产生相应的事件(event)。一个sax解析器解析xml文档的时候,把文档看作为一个流,依次产生相应的事件报告给已注册的content handler, org.xml.sax.contenthandler,如果有错误,错误会报告给error handler, org.xml.sax.errorhandler. 如果你不注册一个error handler,那你就根本不会知道在解析xml文档的时候有没有错误产生和错误是什么。因此,在sax解析xml文档的时候注册一个error handler是极其重要的。 如果程序需要知道有什么事件产生了(并且想处理此事件),那你必须实现org.xml.sax.contenthandler 接口并注册给 sax解析器。一个典型的事件被触发的顺序是 startdocument, startelement, characters, endelement, enddocument。 startdocument 仅仅被触发一次而且是在触发其它event之前。同样,enddocument仅仅被触发一次而且是在整个文档被成功解析之后。你可以从sax javadocs中获取更详细的信息。  figure 2: sax parsing xml 使用jaxp,通过sax parse xml document的代码片断: saxparserfactory spfactory = saxparserfactory.newinstance(); spfactory.setnamespaceaware(true); saxparser saxparser = spfactory.newsaxparser(); //write your handler for processing events and handling error defaulthandler handler = new myhandler(); //parse the xml and report events and errors (if any) to the handler saxparser.parse(new file("data.xml"), handler); 文档对象模型解析 dom 解析是基于对象的原理,当用dom解析xml文档时它会在内存中生成一个树形的结构来表示一个xml文档。树上的每个节点代表着xml文档中的一个节点。如果一个dom解析器符合w3c标准,那它产生的dom就是w3c的dom,使用org.w3c.dom apis就能遍历和修改这个dom。 大部分dom解析器允许你抽取xml文档里的一部分来生成dom树,而不是把整个xml文档在内存中建立对应dom树。  figure 3: dom parsing xml 使用jaxp, 通过dom parse xml document的代码片断: documentbuilderfactory dbfactory = documentbuilderfactory.newinstance(); dbfactory.setnamespaceaware(true); documentbuilder domparser = dbfactory.newdocumentbuilder(); //parse the xml and create the dom document doc = domparser.parse(new file("data.xml")); //to create a new dom from scratch - //document doc = domparser.newdocument(); //once you have the document handle, then you can use //the org.w3c.dom.* apis to traverse or modify the dom... 在校验模式下进行解析 根据dtd校验 dtd 是xml 文档的语法。经常人们会觉得dtd有点另类,因为它和xml的syntax不一样,但dtd是w3c xml1.0里的完整的一部分。如果一份xml文档声明了doctype,并且想在解析的时候根据dtd校验文档,那你必须在适当的factory里启用根据dtd校验文档(validation)这个特性。例如: documentbuilderfactory dbfactory = documentbuilderfactory.newinstance(); dbfactory.setvalidating(true); or saxparserfactory spfactory = saxparserfactory.newinstance(); spfactory.setvalidating(true); 注意,如果xml文档声明了一个dtd ,即使你不启用校验(validation)这个特性,解析器总是试着去读入这个dtd。 这样做的目的是为了保证xml文档中entity reference被正确的扩展了,否则会导致格式不正确的xml文档,只有在xml文档序言部分的声明中standalone属性被置为true时,外部的dtd才会被完全忽略掉。例如: <?xml version="1.1" encoding="utf-8" standalone="yes"?> 根据w3c schema来校验xml文档(wxs) xmlschema 是xml文档的另外一种文法描述。xmlschema非常流行市因为它和xml文档使用同样的语法并且提供了丰富的定义校验限制的特性。如果一个xml文档用"schemalocation" 和"nonamespaceschemalocation"指向了一个schema,结下来你想启用根据xmlschema校验文档这个特性,你还要做如下的步骤: 1.和上面说的一样,调用saxparserfactory o或documentbuilderfactory的setvalidating函数来启用validation这个特性。 2.把属性 "http://java.sun.com/xml/jaxp/properties/schemalanguage" 值设为 "http://www.w3.org/2001/xmlschema" 注意,这种情况下,即使xml文档有doctype声明,处理器仍不会用dtd来校验这个文档。但是和前面提到的一样,为了任何一个entity reference是被正确扩展的,这个dtd还是会被装载的, 既然"schemalocation" 和"nonamespaceschemalocation"仅仅是提示,所以可以使用属性"http://java.sun.com/xml/jaxp/properties/schemasource"从外部提供schemas来覆盖这些提示。 对于这个属性,一些可以接受值是: ?是一个代表schema的url地址的字符串。 ?java.io.inputstream with the contents of the schema ?org.xml.sax.inputsource ?java.io.file ?一个 java.lang.object 的数组,数组内容是上面所提到三类中的一个。 例如: saxparserfactory spfactory = saxparserfactory.newinstance(); spfactory.setnamespaceaware(true); //turn the validation on spfactory.setvalidating(true); //set the validation to be against wxs saxparser.setproperty("http://java.sun.com/xml/jaxp/properties/ schemalanguage", "http://www.w3.org/2001/xmlschema"); //set the schema against which the validation is to be done saxparser.setproperty("http://java.sun.com/xml/jaxp/properties/ schemasource", new file("myschema.xsd")); 使用jaxp的trax apis来进行xml文档转换处理工作 w3c xsl-t 定义了一些转换规则来把源树转化生成结果树。在xsl-t中,转换信息所存在的文件叫样式表(stylesheet)。要用jaxp来转换一个xml文档,你需要
|
|