使用XWAF框架(5)——XML解析器:CXDP

       XWAF推出了自己的组合式XML文档解析器,英文名叫:“CXDP“Combined XML Document Parser”的缩写。核心代码属XWAF原创,注释、日志和帮助文档采用全中文描述,特别适合于中文背景的初级程序员学习和使用。

       CXDP解析器融合了DOM解析DSE解析两种XML解析技术

       DOM解析就是基于文档对象树的解析技术,编码简单,功能强大,且能对XML原文进行“增、删、改、查”操作,是行业内最早推出的XML解析方案,应用广泛,但是对用户计算机的性能和内存要求较高,解析速度稍慢。

       DSEDocument Scanning Events)解析是基于文档扫描事件机制的解析方案。就是以XML原文的节点和元素为最小解析单元,“一边扫描文档内容,一边抛出解析数据”。每次抛出解析数据,就引发一次事件,解析器就会执行与此事件关联的方法。程序员可以在该事件方法中编写捕获数据的代码,为自己所用。DSE解析技术的最大特点,就是“边扫描、边解析、边抛出”,解析器不保存解析的历史数据,交与开发者自己去处理。因此,该方案对计算机的硬件配置和内存要求不高,且解析速度快,特别适合于解析XML大数据文档。与行业内的SAX解析思想一致。

  为了简化编程,CXDP解析器提供了一个名叫XmlManager的管理器类。该类包含创建、解析和保存XML文档的静态方法。方法要求使用者指定XML文件的路径或者符合XML语法规范的字符串。如果希望解析器采用DSE解析模式,则需要用户额外提供一个实现了XmlUserParser<T> 泛型抽象类的实例参数。该实例包括捕获解析数据的各种事件方法,以及返回解析数据的对象类型。若采用DOM解析模式,则不需要此参数。也就是说,开发者调用XmlManager管理器的解析方法时,管理器会自动选择DOM模式或DSE模式来完成解析工作。唯一的差别是提供的参数是否包含XmlUserParser<T>实例。这就简化了应用程序的编码。

       XWAF框架包含CXDP解析器的所有类。如果不想使用XWAF框架,也可以下载或使用独立的压缩文件“com.xwaf.cxdp.jar”来获取CXDP解析器。

5.1  基于DOMXML解析

    DOM解析XML文档的基本步骤,分为以下四步

1)加载XML文档,获取XmlDocument对象。参考代码如下:

String  fileName = "D:\\myXmlFile.xml";

XmlDocument  xd = XmlManager.loadXmlFile(fileName);

2)提取根元素节点对象(XmlElement。参考代码如下:

XmlElement  xeRoot = xd.getDocumentElement();

3)遍历根元素的子节点或后代节点,提取想要的数据。

  参考代码如下:

XmlNodeList xbl = xeRoot.getChildNodes();

for(INode n : xbl.getNodeList()){

if("userName".equals(n.getNodeName())){

......   // 根据用户的XML结构提取数据!

}

}

4销毁XmlDocument对象,释放宝贵的内存资源

  也就是调用文档对象的方法:xd.destroy();

  说明:最核心的解析代码,必须由知道被解析XML文本的结构和各个节点含义的应用程序设计人员根据元素节点的名称,属性节点的设置,以及文本节点与元素节点的父子关系,分别提取相应的属性值,或是文本子节点的内容,来完成XML数据的解析和逻辑组装。用户也可以使用获得的XML数据创建自己的实体对象,然后在应用程序中引用或共享。

  程序员可以根据需求,找到特定的元素节点,并将创建的新元素或文本节点添加到所找到节点的子节点集合中;或者将找到的节点修改或删除后,重新保存到文件,从而实现对原XML文件的增、删、改、查操作。

       CXDP解析器实现了DOM3范的绝大多数接口、类和方法,常用的接口、类和方法如下:

INode接口:是DOM的顶级接口。在DOM对象树中,所有的XML数据项都被看做是节点(Node),包括属性和文本。所以,INode也是最重要的接口,它定义了XML操作的绝大多数方法,如:

getNodeName()方法:获取节点的限定名(包含名称空间前缀)。

getLocalName()方法:获取当前节点的本地名称。

getPrefix()方法:获取节点所属名称空间的前缀。

getNextSibling()方法:获取下一个兄弟节点。

getPreviousSibling()方法:获取上一个兄弟节点。

getParentNode()方法:获取当前节点的父节点。

getFirstChild()方法:获取第一个子节点。

getLastChild()方法:获取最后一个子节点。

getChildNodes()方法:获取当前节点的全部子节点集合。

getNodeType()方法:获取当前节点的类型常量。

getNodeValue()方法:获取节点值。

getTextContent()方法:返回节点及其子孙节点的文本内容。如果文本子孙节点中包含实体引用,将被替换为实体值。

appendChild(INode)方法:将指定的新节点添加到当前节点的子节点集合中;

insertAfter(INode newChild, INode refChild)方法:在指定的子节点之后插入一个新节点。

insertBefore(INode newChild, INode refChild)方法:在指定的子节点前插入一个新节点。

removeChild(INode)方法:移除指定的子节点。

replaceChild(INode newChild, INode oldChild)方法:将当前节点中指定的子节点替换成指定的新节点。

cloneNode(boolean deep):克隆(复制)当前节点对象的副本。

       INode接口还是文档接口(IDocument)和元素接口(IElement)的父接口。

 

XmlNode类:DOM的顶级类,它实现了INode接口的全部方法。是文档类(XmlDocument)和元素类(XmlElement)的父类。

XmlDocumentXML文档节点类,是XmlNode的子类,继承了XmlNode的全部protected属性和方法。另外增加了如下方法:

adoptNode(INode srcNode) :从另一个文档向本文档过继一个节点,并返回过继后的节点。

createElement(String qualifiedName):创建指定限定名(可以包含前缀、冒号和本地名)的元素节点。

createTextNode(String data) :创建带有指定字符串数据的文本节点。

load(String xmlFileName) :将指定的文件名加载到当前文档对象。该方法有四个重载,最重要的重载方法是load(String xmlFileName, XmlUserParser<?> xup, boolean createDOM)方法。该重载方法除了要求指定文件名以外,还要求提供一个实现了泛型抽象类(XmlUserParser<?>)的实例,以及是否创建DOM对象树的参数。如果泛型抽象类参数为null,则第三个参数会自动为true,即自动创建DOM对象树。

 loadXML(String srcXml, String baseURI) :从指定的XML文档片段构建文档对象。第一个参数为文档片段,第二个参数是基础DOM资源标识符(可以为null)。

 saveFile(String xmlFileName, boolean formatXml) :以指定的文件名和格式处理模式将XML文档内容保存到磁盘。第二个参数表示是否对文档内容进行缩进格式化。

 toXmlString(boolean formatXml) :将当前XML文档对象的节点树,根据参数formatXml的值输出为紧凑格式或排版格式的字符串。如果参数formatXmltrue,将对XML内容以元素为单元进行换行和缩进等排版处理。

 

XmlElementXML元素节点类,是XmlNode的子类,继承了XmlNode的全部protected属性和方法。另外增加了如下方法:

 createAttribute(String name, String val) :创建带有指定名称和值的属性节点,并返回创建的 XmlAttribute对象。

 getAttribute(String name):获取指定名称的属性值。

 getAttributeNode(String name)方法:获取指定名称的属性节点对象(XmlAttribute)。

 getAttributes():获取元素的属性集合。

 getElementById(String eId):从文档中查找并返回ID类型的属性值匹配参数值(eId)的第一个元素节点。

 getElementsByTagName(String tagName):获取与指定元素标签名称相匹配的元素节点及其子元素节点的列表。

 getTagName():获取当前元素节点的标签名。

 removeAttribute(String name):删除指定名称的属性节点。

 setAttribute(String name, String value):添加或修改当前元素中,属性名称为 name 的属性值。说明:如不存在同名属性,就添加一个新属性。

 hasAttribute(String name):判断是否存在与指定名称相匹配的属性节点。

5.2  基于DSEXML解析

  采用了XML文档扫描事件机制,要求程序员提供实现了XmlUserParser<T>泛型抽象类的实例参数。XmlUserParser<T> 是一个泛型抽象类,它定义了解析器扫描XML文档的过程中,与扫描事件对应的抽象方法。包括:

1start_Element():该方法在解析遇到一个元素开始节点执行,包括5参数,分别是:父元素的限定名称、元素的本地名称、名称空间的前缀、名称空间标识符、包含的属性集合。

2end_Element()该方法在解析遇到一个元素的结束节点执行,包括2参数,分别是:元素的本地名称、名称空间的前缀。

3Text_Parsed()该方法在解析解析完一个文本节点后被执行,包括2参数,分别是:父元素的限定名称、文本内容。

4EntityReference_Parsed()该方法在解析器解析到一个实体引用节点时执行,包括3参数,分别是:父元素的限定名称、引用实体名、引用实体值(字符串)。

5Comment_Parsed()该方法在解析器解析到一个注释节点时执行,包括2参数,分别是:父元素的限定名称、注释内容。

6ProcessingInstruction_Parsed()该方法在解析器解析到一个XML处理指令节点时执行,包括2参数,分别是:目标处理器名称、处理指令的内容。

7getParsedData():该方法返回用户解析得到的数据对象,其真实类型是程序员事先指定的泛型类。

  程序员可以在自己的实现子类中,选择与要解析的XML文件内容相关的方法并编码实现它,其它的抽象方法可以采用无代码实现!

  注意:编写解析代码时要使用方法中的参数来获取解析器传递出来的数据,并根据XML数据的结构来还原数据逻辑。

  方法getParsedData()”是为方便用户提取解析数据而设计的,程序员应该设计合适的类来存储解析得到的数据,并作为该泛型类的类型参数,也是本方法的返回类型,在实现代码中返回该类型的对象。

  基于DSE的解析特点就是:一边读取XML文档,一边解析XML数据结构,一边抛出各种扫描事件,并通过响应事件的方法参数输出XML数据。所以有人将这种方式称为基于扫描事件的XML解析。该模式的解析步骤分为两步:

1创建继承XmlUserParser<T>的子类,并实现其中的抽象方法;

2调用XmlManager的静态方法parseXml()parseXmlFile(),并将文档内容或文件名,以及XmlUserParser<T>子类对象传递给静态方法

5.3  XmlManager管理类

  该类提供了操作XML文档最基本的静态方法,目的是简化应用程序的编码。

1)loadXml(String, String)方法:加载参数1指定的XML文本,使用并遵循DOM规范,返回一个XmlDocument对象;

2)loadXmlFile(String)方法:加载指定的XML文件,使用和遵循DOM规范,并返回一个XmlDocument文档对象;

3)parseXml(String,XmlUserParser<?>,String)方法快速解析参数1指定的XML文本,但不实现DOM接口,也不返回XmlDocument对象,而是在解析过程中,通过各种解析事件以参数将XML节点和属性数据传递给实现了xmlUserParser<T>的子类实例,该子类在方法中处理解析得到的XML数据。

4)parseXmlFile(String,XmlUserParser<?>)方法parseXml()类似,但它快速解析一个XML文件

5)createXmlDocument()方法创建一个新的XML文档并保存到文件

6)saveXmlToFile(String xmlFileName, String xmlContent)方法保存XML文本到指定的文件。

说明parseXml()parseXmlFile()方法不创建节点树,但要求提供一个实现了XmlUserParser<T>抽象的子类实例。用户在该实例类中要编码实现全部的抽象方法(响应各种解析事件),正是在重写这些抽象方法的代码中,完成了提取和使用XML文档数据的工作。因此,程序员会觉得编码工作比较困难,而且很难同时访问同一个文档中的不同数据。

5.4  小结

  基于DOMXML解析,核心思想是XML文档内容转化为一个节点对象树,可以对树节点进行遍历、添加、修改或删除;当然,还可以创建XML文档功能十分强大且编程简单。因此,常用于XML文档需要频繁改变的服务中。但缺点也非常明显,因为解析器在对XML节点树进行遍历、添加、修改或删除之前,必须先读入整个XML文档,在内存中创建DOM节点对象因此,要消耗大量的内存资源文档比较小,不会造成大的问题XML文档比较大,对内存的需求将成倍增长,这会从解析速度上明显的体现出来,甚至会因内存被消耗殆尽而死机。

  基于DSE的解析,采用了扫描XML文档并抛出解析数据的事件机制,即:一边读入XML内容,一边扫描节点、一边通过节点事件抛出解析数据。解析器并不保存每个XML节点对象,所以内存的消耗与XML文档的大小无关,特别适合于XML大文档快速解析。当然,这种路过式解析并处理数据的策略,不能实现对原文档内容的修改和删除,而且先后抛出的数据之间的逻辑,需要程序员在拦截扫描事件的方法中,自己编写代码进行暂时保存、关联和最终处理。编程难度稍大。好在XWAF提供了XmlUserParser<T>泛型抽象类,提供了应用解析的基本框架和公共处理代码,程序员只需要创建继承子类,并真正实现满足自己功能需求的部分抽象方法,就大功告成。另外,程序员只需要关注、截留和处理自己需要的节点数据,无关的数据可以不管并随即抛弃。即节省了内存资源,有加快了解析速度。对于只读XML解析,DSE是最好的方案!

       CXDP集成了DOMDSE两种解析方案,提供的XmlManager管理器进一步简化了编码,是程序员解析XML文档最好的帮手和选择!

猜你喜欢

转载自www.cnblogs.com/xuzy630/p/XWAF_9.html