原文作者: Rahul Srivastava
原文地址:http://www.xml.com/pub/a/2005/07/06/jaxp.html
中文地址:http://www.matrix.org.cn/resource/article/43/43893_JAXP.html
简介
在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来解析XML文档
JAXP
支持基于对象和基于事件的两种解析方式。基于对象的解析,到目前为止只支持W3C
DOM解析,JAXP的专家组可能在JAXP的将来版本中会支持J-DOM规范。基于事件的解析,只有SAX
解析模式被支持,另一个基于事件的解析模式叫Pull Parsing,本来它应该是JAXP的一部分。但是对于Pull
Parsing存在有一份不同的JSR (#173)文档,也就是大家所知道的Streaming API for XML (StAX)
parsing,现在我们对于那个也没什么更多的可以做了。
使用SAX来解析XML文档
SAX APIs 是在1998年的早些时候由David Megginson提出的,目标是成为基于事件驱动的xml文档解析模式的标准API。即使这样,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中获取更详细的信息。
使用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树。
使用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文
档,你需要定义一个使用样式表来转换XML文档的转换器。创建好这样的转换器后,它把要转换的XML文档作为JAXP的source,返回转换好的结果作
为JAXP的result。目前JAXP提供三种类型的source和result:
StreamSource, SAXSource, DOMSource and StreamResult, SAXResult, DOMResult, 他们是能够联合使用的。
从DOM中生成SAX Events
//parse the XML file to a W3C DOM DocumentBuilderFactory dbfactory = DocumentBuilderFactory.newInstance(); dbfactory.setNamespaceAware(true); DocumentBuilder domparser = dbfactory.newDocumentBuilder(); Document doc = domparser.parse(new File("data.xml")); //prepare the DOM source Source xmlsource = new DOMSource(doc); //create a content handler to handle the SAX events ContentHandler handler = new MyHandler(); //prepare a SAX result using the content handler Result result = new SAXResult(handler); //create a transformer factory TransformerFactory xfactory = TransformerFactory.newInstance(); //create a transformer Transformer xformer = xfactory.newTransformer(); //transform to raise the SAX events from DOM xformer.transform(xmlsource, result);
上面的例子中,我们创建Transformer的时候没有用到XSL。这意味着这个转换器对XML不会有任何的转换,source和result是一样的。当你实际相要用XSL来转换,你应该创建一个使用了XSL的转换器,就像下面一样
//create the xsl source Source xslsource = new StreamSource(new File("mystyle.xsl")); //create the transformer using the xsl source Transformer xformer = xfactory.newTransformer(xslsource);
JAXP1.3有哪些新特性?
除了支持SAX解析,DOM解析,根据DTD/ XMLSchema的校验,使用XSL-T转换,
和以前的版本相比JAXP1.3新支持的特性有:
- XML 1.1 和XML 1.1名字空
- XML Inclusions - XInclude 1.0
- 根据预解析的schema来校验文档
- XPath表达式的计算
- 以前XMLSchema 1.0, XPath 2.0 和XQuery 1.0中的某些数据类型不能被映射到java里的数据类型,现在可以了。
使用JAXP1.3
XML1.1主要支持的特性如下:
- 向前兼容不断增长的Unicode字符集。
- 在行结束(line-end)字符集中新添加了NEL (#x85)和Unicode行分隔符(#x2028)。
XML1.1中的变更不是向下兼容的,XML1.0中的一些well-formedness规则在
XML1.1中可能就不适用。所以XML1.1的规范是全新的而不是从XML1.0规范上升级。
为了能够使用XML1.1和XML1.1的名字空间,你必须在XML序言声明中把version属性的值设为"1.1"。例如:
<?xml version="1.1" encoding="UTF-8" standalone="yes"?>
XInclude允许一个XML文档包含另一个XML文档,例如:
<myMainXMLDoc xmlns:xi="http://www.w3.org/2001/XInclude"> <xi:include href="fragment.xml"/> ... </myMainXMLDoc>
想要使用XML inclusions特性,你必须在适当的factory里设置XInclude属性为true,就像下面代码所示:
DocumentBuilderFactory dbfactory = DocumentBuilderFactory.newInstance(); dbfactory.setXIncludeAware(true);
根据预解析的schema校验JAXP的输入源
javax.xml.validation
包提供了解析schema和根据预解析的schema校验XML文档的功能。DOMSource和SAXSource是可以根据预解析的schema来被
校验。如果需要可以缓存预解析的schema来达到优化的目的。必须注意到的是,根据预解析的schema校验JAXP的输入源
中,StreamSource并不是被支持的源,还有schema可以是W3C XML Schema 或者是一个OASIS RELAX-NG。例如:
//parse an XML in non-validating mode and create a DOMSource DocumentBuilderFactory dbfactory = DocumentBuilderFactory.newInstance(); dbfactory.setNamespaceAware(true); dbfactory.setXIncludeAware(true); DocumentBuilder parser = dbfactory.newDocumentBuilder(); Document doc = parser.parse(new File("data.xml")); DOMSource xmlsource = new DOMSource(doc); //create a SchemaFactory for loading W3C XML Schemas SchemaFactory wxsfactory = SchemaFactory.newInstance(XMLConstants.W3C_XML_SCHEMA_NS_URI); //set the errorhandler for handling errors in schema itself wxsfactory.setErrorHandler(schemaErrorHandler); //load a W3C XML Schema Schema schema = wxsfactory.newSchema(new File("myschema.xsd")); // create a validator from the loaded schema Validator validator = schema.newValidator(); //set the errorhandler for handling validation errors validator.setErrorHandler(validationErrorHandler); //validate the XML instance validator.validate(xmlsource);
计算XPath表达式
javax.xml.xpath 包提供了根据XML文档计算XPath表达式的功能。如果一个表达式要被重用,出于性能考虑,这个XPath表达式会被编译。
顺便说一下,JAXP中的XPath
的API被设计为无状态的,这就意味着每次你要计算一个XPath表达式,你都要传入一个XML的文档。通常,很多XPath表达式是根据单个XML文档
来计算的。这种情况下,如果JAXP中的XPath
APIs是有状态的,XML文档只需传入一次,那样就更好了。对于底层实现来说就多了一个优化选择,可以把XML
文档源存储起来,这样就可以快速计算XPath表达式了。
一个根据XML文档计算XPath表达式得例子:
<?xml version="1.0"?> <employees> <employee> <name>e1</name> </employee> <employee> <name>e2</name> </employee> </employees>
//parse an XML to get a DOM to query DocumentBuilderFactory dbfactory = DocumentBuilderFactory.newInstance(); dbfactory.setNamespaceAware(true); dbfactory.setXIncludeAware(true); DocumentBuilder parser = dbfactory.newDocumentBuilder(); Document doc = parser.parse(new File("data.xml")); //get an XPath processor XPathFactory xpfactory = XPathFactory.newInstance(); XPath xpathprocessor = xpfactory.newXPath(); //set the namespace context for resolving prefixes of the Qnames //to NS URI, if the xpath expresion uses Qnames. XPath expression //would use Qnames if the XML document uses namespaces. //xpathprocessor.setNamespaceContext(NamespaceContext nsContext); //create XPath expressions String xpath1 = "/employees/employee"; XPathExpression employeesXPath = xpathprocessor.compile(xpath1); String xpath2 = "/employees/employee[1]"; XPathExpression employeeXPath = xpathprocessor.compile(xpath2); String xpath3 = "/employees/employee[1]/name"; XPathExpression empnameXPath = xpathprocessor.compile(xpath3); //execute the XPath expressions System.out.println("XPath1="+xpath1); NodeList employees = (NodeList)employeesXPath.evaluate(doc, XPathConstants.NODESET); for (int i=0; i<employees.getLength(); i++) { System.out.println(employees.item(i).getTextContent()); } System.out.println("XPath2="+xpath2); Node employee = (Node)employeeXPath.evaluate(doc, XPathConstants.NODE); System.out.println(employee.getTextContent()); System.out.println("XPath3="+xpath3); String empname = empnameXPath.evaluate(doc); System.out.println(empname);
XML和java数据类型间的映射
Datatypes
在XMLSchema1.0的时候就很流行了,被很多其他XML规范所应用,像
XPath,XQuery,WSDL等。大部分的数据类型可以映射到java的基本数据类型或包装过的数据类型。其他的类型
如:dataTime,duration可以被映射到新的java数据类型:
javax.xml.datatype.XMLGregorianCalendar, javax.xml.datatype.Duration,
and javax.xml.namespace.QName. 这样XMLSchema1.0 XPath 2.0 和XQuery
1.0中所有数据类型,JAVA中都有对应的类型存在。
从可用性角度看,如果DatatypeFactory有方法能够生成一个对应WXS中数据类型的java对象,并且这个java对象拥有方法能根据facets限制数据类型和根据值来校验数据类型,这样就非常好了。
一个使用Oracle's XDK的例子:
import oracle.xml.parser.schema.*; . . . //create a simpleType object XSDSimpleType st = XSDSimpleType.getPrimitiveType(XSDSimpleType.iSTRING); //set a constraining facet on the simpleType st.setFacet(XSDSimpleType.LENGTH, "5"); //validate value st.validateValue("hello");
底层实现间的切换
一个JAXP的实现通常包括一个默认的解析器,转换器,xpath引擎和schema校验器,
但
是就像文章开始的时候所提到的那样,JAXP是一个可插拔的API,我们可以插入我们自己的处理器来替换JAXP默认的处理器。要实现这样的切换,我们可
以通过设置属性javax.xml.xxx.yyyFactory的值来指定一个合格的factory的实现类。当
yyyFactory.newInstance()被调用的时候,JAXP使用如下的顺序查找需要装载的具体的实现类:
- 使用javax.xml.xxx.yyyFactory属性指定的值
- 使用 JRE 目录下lib/jaxp.properties 属性文件。Jaxp.properties文件只被读入一次,它的值会被缓存已被将来所用。如果第一次尝试去读这个文件而此文件不存在的话,以后就不会尝 试着去检查此文件是否存在。jaxp.properties里面的值第一次读过之后,就不可能被修改了。
- 如果可以地话,可以使用 Services API(在JAR的规范里有详细的信息)来决定哪个实现类被载入。Services API会在runtime时存在的jars的META-INF/services/javax.xml.xxx.yyyFactory里寻找那个 classname。
- 使用平台默认的javax.xml.xxx.yyyFactory 实例。
javax.xml.xxx.yyyFactory 可是下面其中的一个:
- javax.xml.parsers.SAXParserFactory
- javax.xml.parsers.DocumentBuilderFactory
- javax.xml.transform.TransformerFactory
- javax.xml.xpath.XPathFactory
- javax.xml.validation.SchemaFactory:schemaLanguage (schemaLanguage 是调用SchemaFactory的newInstance函数时所提供的参数)
例如:想在JAXP中使用SAX解析器,你可以用上面提到的4个方法中的任何一个把
javax.xml.parsers.SAXParserFactory设为org.apache.xerces.jaxp.SAXParserFactoryImpl。
其中的一个方法如下:
java -Djavax.xml.parsers.SAXParserFactory= org.apache.xerces.jaxp.SAXParserFactoryImpl MyApplicationProgram
发表评论
-
java concurrency
2011-05-18 10:22 0Multi-threading - Multiple th ... -
Why Prepared Statements are important and how to use them "properly"
2011-05-11 16:10 1098Databases have a tough job. T ... -
JDBC基础教程
2011-05-11 14:46 0转自 http://www.yesky.com/SoftCh ... -
Why ConcurrentHashMap is better than Hashtable and just as good as a HashMap
2011-03-29 13:43 812Original from Why ConcurrentHas ...
相关推荐
### JAXP的演进与未来 随着时间的推移,JAXP也在不断发展,以适应不断变化的XML标准和技术需求。尽管最初的设计可能显得简单,仅包含少量的核心类,但随着功能的扩展和优化,JAXP逐渐成为了Java世界中不可或缺的一...
随着技术的进步和需求的变化,JAXP也将不断演进和发展。未来的发展方向可能包括: - **更高的性能**:进一步优化算法和架构,提高处理速度。 - **更多的功能**:增加对新兴XML标准和技术的支持。 - **更好的易用性*...
第五章“XSLT Processing with Java”通过一个简单的例子,引入了JAXP 1.1(Java API for XML Processing),讲解了输入与输出的处理方式,以及样式表编译的过程。这一章节对于希望在Java程序中集成XSLT转换功能的...
10. **JAXP(Java API for XML Processing)**和**JAXB(Java Architecture for XML Binding)**:这两者提供了处理XML文档的工具,JAXP用于解析和生成XML,JAXB用于将Java对象转换为XML和反之亦然。 J2EE企业级...
3. **版本演进** J2EE后续演变为Java EE,再到现在的Jakarta EE,持续更新以适应新的技术趋势,例如微服务、云原生和响应式编程。 4. **测试与调试** J2EE应用的测试涵盖单元测试、集成测试和性能测试,工具如...
- **XPath和XSLT支持**:JAXP(Java API for XML Processing)增强了XPath和XSLT处理,方便XML数据的查询和转换。 - **JMX增强**:提高了Java Management Extensions的易用性和功能,便于管理和监控Java应用。 2....
6. **XML处理增强**:JAXB(Java Architecture for XML Binding)和JAXP(Java API for XML Processing)的改进,使得XML数据与Java对象之间的转换更为便捷。 描述中提到这个版本是“免安装”的,这意味着它是一个...
- **JAXP兼容的XML解析器**:Ant需要JAXP兼容的XML解析器,二进制版本自带Apache Xerces 2。若需使用其他解析器,需调整lib目录下的配置。 - **JDK版本**:当前版本的Ant要求JDK 1.2或更高版本。注意,Microsoft JVM...
12. **Web Services**: 虽然SOAP和WSDL规范在J2EE 1.4中还不是标准,但通过Java API for XML Processing (JAXP)、Java API for XML Messaging (JAXM)和Java API for XML Web Services (JAX-RPC),开发者可以构建和...
Java 2,企业版(J2EE)是一个广泛采用的企业级开发框架,旨在为软件开发者提供...随着技术的发展,J2EE不断演进,以适应新的挑战和需求,如后来的Java EE(现在称为Jakarta EE),继续推动着企业级应用的创新和发展。
同时,它提供了多种绑定,如Java to Protocol (JAXP)、Java to XML Data Binding (JAXB)等。 7. **集成性**:Apache CXF可以方便地与Spring框架集成,提供服务组件管理、依赖注入等功能。此外,它也支持OSGi环境。 ...
4. 默认方法:接口中可以定义带有实现的方法,这使得接口可以随着时间演进而添加新功能,同时保持向后兼容。 5. Date和Time API的重构:Java 8引入了全新的java.time包,取代了过时的java.util.Date和java.util....
标题 "axis jar包下载" 指的是AXIS框架的核心库文件,这...虽然现在有更多现代化的Web服务框架,如Spring Boot和JAX-WS,但对于那些需要维护旧系统或者研究Web服务历史演进的开发者来说,AXIS仍然是一个有价值的工具。
这些版本之间的对比展示了Java EE如何随着技术发展而演进,不断优化开发者的体验,提升企业级应用的性能和安全性。例如,从J2EE 1.3到Java EE 5.0,EJB从复杂的组件模型简化为更加轻量级,JSP和Servlet也得到了增强...
随着技术的演进,Java EE在后续的版本中不断引入新的特性,如CDI(Contexts and Dependency Injection)、JSF 2.x、Java Persistence API (JPA)、Java EE 7的WebSocket支持等,进一步提高了开发效率和系统的可扩展性...
6. **标准库和API使用**:Java提供了大量的标准库,如JDBC(数据库连接)、JAXP(XML处理)等,源代码中可能会使用到这些API。 7. **设计模式**:源代码可能会采用常见的设计模式,如工厂模式、单例模式、观察者...
### Java平台概述 Java平台是一种广泛使用的编程语言和运行环境,它支持跨平台的应用程序开发。Java平台由多个组成部分构成,这些部分...此外,Java平台还不断演进,引入新的特性和改进,以适应不断变化的技术需求。