XML解析

来源:互联网 发布:成都家电维修软件 编辑:程序博客网 时间:2024/06/05 19:17

XML编程

<?xml version="1.0" encoding="UTF-8"?>
<student>//实体
<name id="001">张三</name>
<sex>男</sex>
<age>20</age>
</student>


//xml可扩展标记语言,跨平台,跨网络,跨程序的语言描述方式,实现数据交换系统配置内容管理等


//DTD文档类型定义




XML文档的组成
一个XML文件一般由以下几部分组成:
文档声明
元素
元素的属性
注释
CDATA区
特殊字符
处理指令(PI:Processing Instruction)


文档声明
在编写XML文档时,需要先使用文档声明来声明XML文档。且必须出现在文档的第一行。
最简单的语法:<?xml version=“1.0”?>
用encoding属性说明文档所使用的字符编码,默认为UTF-8。保存在磁盘上的文件编码要与声明的编码一致。
如:<?xml version=“1.0” encoding=“GB2312”?>
用standalone属性说明文档是否独立,即是否依赖其他文档。
如:<?xml version=“1.0” standalone=“yes”?>


元素(1)
XML元素指XML文件中出现的标签。一个标签分为起始和结束标签(不能省略)。一个标签有如下几种书写形式:
包含标签主体:<mytag>some content</mytag>
不含标签主体:<mytag/> ==   <mytag></mytag>     <br/><hr/>
一个标签中可以嵌套若干子标签,但所有标签必须合理的嵌套,不允许有交叉嵌套。
<mytag1><mytag2></mytag1></mytag2>   WRONG
一个XML文档必须有且仅有一个根标签,其他标签都是这个根标签的子标签或孙标签。
元素命名规范
元素(标签)的名称可以包含字母、数字、减号、下划线和英文句点,但必须遵守下面的一些规范:
严格区分大小写;<P> <p>
只能以字母或下划线开头;abc _abc
不能以xml(或XML、Xml等)开头----W3C保留日后使用;
名称字符之间不能有空格或制表符;ab
名称字符之间不能使用冒号; (有特殊用途)


元素的属性
一个元素可以有多个属性,每个属性都有它自己的名称和取值,例如:<mytag name=“value” …/>
属性值一定要用引号(单引号或双引号)引起来。
属性名称的命名规范与元素的命名规范相同
元素中的属性是不允许重复的
在XML技术中,标签属性所代表的信息也可以被改成用子元素的形式来描述,例如:
<mytag>
<name>
<firstName/>
<lastName/>
</name>
</mytag>


XML约束之DTD
为什么需要约束
XML都是用户自定义的标签,若出现小小的错误,软件程序将不能正确地获取文件中的内容而报错。(如:Tomcat)
XML技术中,可以编写一个文档来约束一个XML的书写规范,这个文档称之为约束。
两个概念:
格式良好的XML:遵循XML语法的XML
有效的XML:遵循约束文档的XML
总之:约束文档定义了在XML中允许出现的元素名称、属性及元素出现的顺序等等。


常用的约束技术
XML DTD


验证XML的有效性
如何根据DTD中定义的内容来验证XML书写是否正确呢?
答:需要软件程序,即解析器


根据能否对XML文档进行约束模式校验,可以将解析器分为两类:
非校验解析器,如IE
校验解析器
编程校验XML文档的正确性
IE5以上浏览器内置了XML解析工具:Microsort.XMLDOM,开发人员可以编写javascript代码,利用这个解析工具装载xml文件,并对xml文件进行dtd验证。
创建xml文档解析器对象
var xmldoc = new ActiveXObject("Microsoft.XMLDOM");
开启xml校验
xmldoc.validateOnParse = "true";
装载xml文档
xmldoc.load("book.xml");
获取错误信息
xmldoc.parseError.reason;  
xmldoc.parseError.line
编写DTD的方式


DTD语法细节
DTD文档的语法主要涉及以下内容的定义:
定义元素
定义属性
定义实体
DTD-定义元素
在DTD文档中使用ELEMENT关键字来声明一个XML元素。
语法:<!ELEMENT 元素名称 使用规则>
使用规则:
(#PCDATA):指示元素的主体内容只能是普通的文本.(Parsed Character Data)
EMPTY:用于指示元素的主体为空。比如<br/>
ANY:用于指示元素的主体内容为任意类型。
(子元素):指示元素中包含的子元素
定义子元素及描述它们的关系:


如果子元素用逗号分开,说明必须按照声明顺序去编写XML文档。
如: <!ELEMENT FILE (TITLE,AUTHOR,EMAIL)
如果子元素用“|”分开,说明任选其一。
如:<!ELEMENT FILE (TITLE|AUTHOR|EMAIL)
用+、*、?来表示元素出现的次数
如果元素后面没有+*?:表示必须且只能出现一次
+:表示至少出现一次,一次或多次
*:表示可有可无,零次、一次或多次
?:表示可以有也可以无,有的话只能有一次。零次或一次
如: <!ELEMENT MYFILE ((TITLE*, AUTHOR?, EMAIL)* | COMMENT)>


DTD--定义属性示例
1、<!ATTLIST 页面作者 
    姓名 CDATA #IMPLIED 
    年龄 CDATA #IMPLIED 
    联系信息 CDATA #REQUIRED 
    网站职务 CDATA #FIXED "页面作者" 
    个人爱好 CDATA "上网"
       > 
2、<?xml version = "1.0" encoding="GB2312" standalone="yes"?>
<!DOCTYPE 购物篮 [
<!ELEMENT 肉 EMPTY>
<!ATTLIST 肉 品种 ( 鸡肉 | 牛肉 | 猪肉 | 鱼肉 ) "鸡肉">
]> 
<购物篮>
<肉 品种="鱼肉"/>
<肉 品种="牛肉"/>
<肉/>
</购物篮>


DTD--定义实体


定义实体就是为一段内容指定一个名称,使用时通过这个名称就可以引用其所代表的内容。
在DTD文档中使用ENTITY关键字来声明一个实体。
实体可分为:引用实体和参数实体,两者的语法不同
Java解析XML概述
XML解析方式分为两种:DOM方式和SAX方式
DOM:Document Object Model,文档对象模型。这种方式是W3C推荐的处理XML的一种方式。
SAX:Simple API for XML。这种方式不是官方标准,属于开源社区XML-DEV,几乎所有的XML解析器都支持它。
XML解析开发包
JAXP:是SUN公司推出的解析标准实现。JDK
Dom4J:是开源组织推出的解析开发包。(牛,大家都在用,包括SUN公司的一些技术的实现都在用)
JDom:是开源组织推出的解析开发包。


JAXP
JAXP:(Java API for XML Processing)开发包是JavaSE的一部分,它由以下几个包及其子包组成:
org.w3c.dom:提供DOM方式解析XML的标准接口
org.xml.sax:提供SAX方式解析XML的标准接口
javax.xml:提供了解析XML文档的类
javax.xml.parsers包中,定义了几个工厂类。我们可以通过调用这些工厂类,得到对XML文档进行解析的DOM和SAX解析器对象。
DocumentBuilderFactory
SAXParserFactory
获得JAXP中的DOM解析器
调用 DocumentBuilderFactory.newInstance() 方法得到创建 DOM 解析器的工厂。


调用工厂对象的 newDocumentBuilder方法得到 DOM 解析器对象。


调用 DOM 解析器对象的 parse() 方法解析 XML 文档,得到代表整个文档的 Document 对象,进行可以利用DOM特性对整个XML文档进行操作了。


DOM编程
DOM模型(document object model)
DOM解析器在解析XML文档时,会把文档中的所有元素,按照其出现的层次关系,解析成一个个Node对象(节点)。
在dom中,节点之间关系如下:
位于一个节点之上的节点是该节点的父节点(parent)
一个节点之下的节点是该节点的子节点(children) 
同一层次,具有相同父节点的节点是兄弟节点(sibling) 
一个节点的下一个层次的节点集合是节点后代(descendant)
父、祖父节点及所有位于节点上面的,都是节点的祖先(ancestor) 
节点类型(下页ppt)


Node对象
Node对象提供了一系列常量来代表结点的类型,当开发人员获得某个Node类型后,就可以把Node节点转换成相应的节点对象(Node的子类对象),以便于调用其特有的方法。(查看API文档) 
Node对象提供了相应的方法去获得它的父结点或子结点。编程人员通过这些方法就可以读取整个XML文档的内容、或添加、修改、删除XML文档的内容了。


DOM方式解析XML文件
DOM解析编程
1、得到某个具体的节点内容
2、遍历所有元素节点
3、修改某个元素节点的主体内容
4、向指定元素节点中增加子元素节点
5、向指定元素节点上增加同级元素节点
6、删除指定元素节点
7、操作XML文件属性
DOM编程练习


更新XML文档
javax.xml.transform包中的Transformer类用于把代表XML文件的Document对象转换为某种格式后进行输出,例如把xml文件应用样式表后转成一个html文档。利用这个对象,当然也可以把Document对象又重新写入到一个XML文件中。
Transformer类通过transform方法完成转换操作,该方法接收一个源和一个目的地。我们可以通过:
javax.xml.transform.dom.DOMSource类来关联要转换的document对象, 
用javax.xml.transform.stream.StreamResult 对象来表示数据的目的地。
 Transformer对象通过TransformerFactory获得。


SAX解析
在使用 DOM 解析 XML 文档时,需要读取整个 XML 文档,在内存中构架代表整个 DOM 树的Doucment对象,从而再对XML文档进行操作。此种情况下,如果 XML 文档特别大,就会消耗计算机的大量内存,并且容易导致内存溢出。


SAX解析允许在读取文档的时候,即对文档进行处理,而不必等到整个文档装载完才会文档进行操作。


SAX解析
SAX采用事件处理的方式解析XML文件,利用 SAX 解析 XML 文档,涉及两个部分:解析器和事件处理器:
解析器可以使用JAXP的API创建,创建出SAX解析器后,就可以指定解析器去解析某个XML文档。
解析器采用SAX方式在解析某个XML文档时,它只要解析到XML文档的一个组成部分,都会去调用事件处理器的一个方法,解析器在调用事件处理器的方法时,会把当前解析到的xml文件内容作为方法的参数传递给事件处理器。
事件处理器由程序员编写,程序员通过事件处理器中方法的参数,就可以很轻松地得到sax解析器解析到的数据,从而可以决定如何对数据进行处理。


SAX方式解析XML文档
使用SAXParserFactory创建SAX解析工厂
SAXParserFactory spf = SAXParserFactory.newInstance();
通过SAX解析工厂得到解析器对象
SAXParser sp = spf.newSAXParser();
通过解析器对象得到一个XML的读取器
XMLReader xmlReader = sp.getXMLReader();
设置读取器的事件处理器
xmlReader.setContentHandler(new BookParserHandler());
解析xml文件
xmlReader.parse("book.xml");


DOM4J解析XML文档
Dom4j是一个简单、灵活的开放源代码的库。Dom4j是由早期开发JDOM的人分离出来而后独立开发的。与JDOM不同的是,dom4j使用接口和抽象基类,虽然Dom4j的API相对要复杂一些,但它提供了比JDOM更好的灵活性。 
Dom4j是一个非常优秀的Java XML API,具有性能优异、功能强大和极易使用的特点。现在很多软件采用的Dom4j,例如Hibernate,包括sun公司自己的JAXM也用了Dom4j。
使用Dom4j开发,需下载dom4j相应的jar文件。




Document对象
DOM4j中,获得Document对象的方式有三种:


1.读取XML文件,获得document对象            
                   SAXReader reader = new SAXReader();
              Document   document = reader.read(new File("input.xml"));


2.解析XML形式的文本,得到document对象.
                   String text = "<members></members>";
              Document document = DocumentHelper.parseText(text);


3.主动创建document对象.
                  Document document = DocumentHelper.createDocument();
             //创建根节点
                  Element root = document.addElement("members");




节点对象
1.获取文档的根节点.
      Element root = document.getRootElement();


2.取得某个节点的子节点.
Element element=node.element(“书名");


3.取得节点的文字
      String text=node.getText();
4.取得某节点下所有名为“member”的子节点,并进行遍历.
 List nodes = rootElm.elements("member");
 
  for (Iterator it = nodes.iterator(); it.hasNext();) {
     Element elm = (Element) it.next();
    // do something
 }


5.对某节点下的所有子节点进行遍历.
    for(Iterator it=root.elementIterator();it.hasNext();){
       Element element = (Element) it.next();
       // do something
    }


6.在某节点下添加子节点.
Element ageElm = newMemberElm.addElement("age");
7.设置节点文字.
 element.setText("29");


8.删除某节点.
//childElm是待删除的节点,parentElm是其父节点
    parentElm.remove(childElm);


9.添加一个CDATA节点.
Element contentElm = infoElm.addElement("content");
contentElm.addCDATA(diary.getContent());


节点对象属性 
1.取得某节点下的某属性
    Element root=document.getRootElement();    
    //属性名name
         Attribute attribute=root.attribute("size");


2.取得属性的文字
    String text=attribute.getText();


 3.删除某属性
 Attribute attribute=root.attribute("size");
 root.remove(attribute);


3.遍历某节点的所有属性
   Element root=document.getRootElement();    
   for(Iterator it=root.attributeIterator();it.hasNext();){
         Attribute attribute = (Attribute) it.next();
         String text=attribute.getText();
         System.out.println(text);
    }


4.设置某节点的属性和文字.
   newMemberElm.addAttribute("name", "sitinspring");


5.设置属性的文字
   Attribute attribute=root.attribute("name");
   attribute.setText("sitinspring");




将文档写入XML文件. 
1.文档中全为英文,不设置编码,直接写入的形式.
  XMLWriter writer = new XMLWriter(new  FileWriter("output.xml"));
  writer.write(document);
  writer.close();


2.文档中含有中文,设置编码格式写入的形式.
OutputFormat format = OutputFormat.createPrettyPrint();
// 指定XML编码                   
     format.setEncoding("GBK");       
XMLWriter writer = new XMLWriter(new FileOutputStream ("output.xml"),format);
writer.write(document);
writer.close();


Dom4j在指定位置插入节点 
1.得到插入位置的节点列表(list)
2.调用list.add(index,elemnent),由index决定element的插入位置。
Element元素可以通过DocumentHelper对象得到。示例代码:


Element aaa = DocumentHelper.createElement("aaa");
aaa.setText("aaa");


List list = root.element("书").elements();
list.add(1, aaa);


//更新document


字符串与XML的转换 
1.将字符串转化为XML
 
     String text = "<members> <member>sitinspring</member></members>";
Document document = DocumentHelper.parseText(text);


2.将文档或节点的XML转化为字符串.


     SAXReader reader = new SAXReader();
Document   document = reader.read(new File("input.xml"));            
Element root=document.getRootElement();    
            
String docXmlText=document.asXML();


String rootXmlText=root.asXML();
Element memberElm=root.element("member");
String memberXmlText=memberElm.asXML();


XML Schema
XML Schema 也是一种用于定义和描述 XML 文档结构与内容的模式语言,其出现是为了克服 DTD 的局限性
XML Schema VS DTD:
XML Schema符合XML语法结构。 
DOM、SAX等XML API很容易解析出XML Schema文档中的内容。 
XML Schema对名称空间支持得非常好。 
XML Schema比XML DTD支持更多的数据类型,并支持用户自定义新的数据类型。 
XML Schema定义约束的能力非常强大,可以对XML实例文档作出细致的语义限制。
XML Schema不能像DTD一样定义实体,比DTD更复杂,但Xml Schema现在已是w3c组织的标准,它正逐步取代DTD。  


Schema约束快速入门
XML Schema 文件自身就是一个XML文件,但它的扩展名通常为.xsd。
一个XML Schema文档通常称之为模式文档(约束文档),遵循这个文档书写的xml文件称之为实例文档。
和XML文件一样,一个XML Schema文档也必须有一个根结点,但这个根结点的名称为schema。
编写了一个XML Schema约束文档后,通常需要把这个文件中声明的元素绑定到一个URI地址上,在XML Schema技术中有一个专业术语来描述这个过程,即把XML Schema文档声明的元素绑定到一个名称空间上,以后XML文件就可以通过这个URI(即名称空间)来告诉解析引擎,xml文档中编写的元素来自哪里,被谁约束。


Schema入门案例
<?xml version="1.0" encoding="UTF-8" ?> 
<xs:schema xmlns:xs=“http://www.w3.org/2001/XMLSchema” //标准的名称空间
 targetNamespace=“http://www. itcast.cn” //将该schema文档绑定到http://www.itcast.cn名称空间
 elementFormDefault="qualified">
<xs:element name='书架' >
<xs:complexType>
<xs:sequence maxOccurs='unbounded' >
<xs:element name='书' >
<xs:complexType>
<xs:sequence>
<xs:element name='书名' type='xs:string' />
<xs:element name='作者' type='xs:string' />
<xs:element name='售价' type='xs:string' />
</xs:sequence>
</xs:complexType>
</xs:element>
</xs:sequence>
</xs:complexType>
</xs:element>
</xs:schema>


Schema入门案例
<?xml version="1.0" encoding="UTF-8"?>


<itcast:书架 xmlns:itcast="http://www.itcast.cn"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation=“http://www.itcast.cn book.xsd">


<itcast:书>
<itcast:书名>JavaScript网页开发</itcast:书名>
<itcast:作者>张孝祥</itcast:作者>
<itcast:售价>28.00元</itcast:售价>
</itcast:书>
</itcast:书架>


名称空间的概念 
在XML Schema中,每个约束模式文档都可以被赋以一个唯一的名称空间,名称空间用一个唯一的URI(Uniform Resource Identifier,统一资源标识符)表示。 在Xml文件中书写标签时,可以通过名称空间声明(xmlns),来声明当前编写的标签来自哪个Schema约束文档。如:
<itcast:书架 xmlns:itcast=“http://www.itcast.cn”>
<itcast:书>……</itcast:书>
</itcast:书架>
此处使用itcast来指向声明的名称,以便于后面对名称空间的引用。
注意:名称空间的名字语法容易让人混淆,尽管以 http:// 开始,那个 URL 并不指向一个包含模式定义的文件。事实上,这个 URL:http://www.itcast.cn根本没有指向任何文件,只是一个分配的名字。


使用名称空间引入Schema
为了在一个XML文档中声明它所遵循的Schema文件的具体位置,通常需要在Xml文档中的根结点中使用schemaLocation属性来指定,例如:
<itcast:书架 xmlns:itcast="http://www.itcast.cn"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation=“http://www.itcast.cn book.xsd">
schemaLocation此属性有两个值。第一个值是需要使用的命名空间。第二个值是供命名空间使用的 XML schema 的位置,两者之间用空格分隔。
注意,在使用schemaLocation属性时,也需要指定该属性来自哪里。


使用默认名称空间 
基本格式:
xmlns="URI"  
举例:
<书架 xmlns="http://www.it315.org/xmlbook/schema"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation=“http://www.itcast.cn book.xsd">
<书>
<书名>JavaScript网页开发</书名>
<作者>张孝祥</作者>
<售价>28.00元</售价>
</书>
<书架>


使用名称空间引入多个XML Schema文档 
文件清单:xmlbook.xml
<?xml version="1.0" encoding="UTF-8"?>


<书架 xmlns="http://www.it315.org/xmlbook/schema" 
xmlns:demo="http://www.it315.org/demo/schema"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://www.it315.org/xmlbook/schema  http://www.it315.org/xmlbook.xsd 
http://www.it315.org/demo/schema http://www.it315.org/demo.xsd">
<书>
<书名>JavaScript网页开发</书名>
<作者>张孝祥</作者>
<售价 demo:币种=”人民币”>28.00元</售价>
</书>
</书架>


不使用名称空间引入XML Schema文档
文件清单:xmlbook.xml
<?xml version="1.0" encoding="UTF-8"?>
<书架 xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:noNamespaceSchemaLocation="xmlbook.xsd">
<书>
<书名>JavaScript网页开发</书名>
<作者>张孝祥</作者>
<售价>28.00元</售价>
</书>
</书架>


在XML Schema文档中声明名称空间
<xs:schema xmlns:xs="http://www.w3.org/2001/XMLSchema"
      targetNamespace="http://www. itcast.cn"
      elementFormDefault="qualified">
<xs:schema>


targetNamespace元素用于指定schema文档中声明的元素属于哪个名称空间。
elementFormDefault元素用于指定,该schema文档中声明的根元素及其所有子元素都属于targetNamespace所指定的名称空间。

DOM解析XML

package com.java1234.xml;


import javax.xml.parsers.DocumentBuilder;
import javax.xml.parsers.DocumentBuilderFactory;


import org.w3c.dom.Document;
import org.w3c.dom.Element;
import org.w3c.dom.NodeList;


public class DOM01 {//DOM解析,把整个xml文档加载到内存转化成DOM树,随机访问dom树的任何数据。灵活速度快,消耗资源多


public static void main(String[] args) {
DocumentBuilderFactory factory=DocumentBuilderFactory.newInstance();//文档构建工厂获取实例
try {
DocumentBuilder builder=factory.newDocumentBuilder();//文档构建模型
Document doc=builder.parse("src/student.xml");//通过build解析student
NodeList nodeList=doc.getElementsByTagName("student");//获取dom节点
Element e=(Element)nodeList.item(0);//有很多students//获取元素
System.out.println("姓名:"+e.getElementsByTagName("name").item(0).getFirstChild().getNodeValue());//获取文本节点值
System.out.println("性别:"+e.getElementsByTagName("sex").item(0).getFirstChild().getNodeValue());
System.out.println("年龄:"+e.getElementsByTagName("age").item(0).getFirstChild().getNodeValue());
} catch (Exception e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
}
}




package com.java1234.xml;


import javax.xml.parsers.DocumentBuilder;
import javax.xml.parsers.DocumentBuilderFactory;


import org.w3c.dom.Document;
import org.w3c.dom.Element;
import org.w3c.dom.NamedNodeMap;
import org.w3c.dom.Node;
import org.w3c.dom.NodeList;


public class DOM02 {


public static void printNodeAttr(Node node){
NamedNodeMap namedNodeMap=node.getAttributes();
for(int i=0;i<namedNodeMap.getLength();i++){
Node attrNode=namedNodeMap.item(i);//ID是节点node
System.out.println(attrNode.getNodeName()+":"+attrNode.getFirstChild().getNodeValue());
}
}

public static void main(String[] args) {
DocumentBuilderFactory factory=DocumentBuilderFactory.newInstance();
try {
DocumentBuilder builder=factory.newDocumentBuilder();
Document doc=builder.parse("src/students.xml");
NodeList nodeList=doc.getElementsByTagName("students");
Element element=(Element)nodeList.item(0);
NodeList studentsNodeList=element.getElementsByTagName("student");//真正的节点nodelist
for(int i=0;i<studentsNodeList.getLength();i++){
Element e=(Element)studentsNodeList.item(i);
System.out.println("姓名:"+e.getElementsByTagName("name").item(0).getFirstChild().getNodeValue());
printNodeAttr(e.getElementsByTagName("name").item(0));//获取属性节点id=2
System.out.println("性别:"+e.getElementsByTagName("sex").item(0).getFirstChild().getNodeValue());
System.out.println("年龄:"+e.getElementsByTagName("age").item(0).getFirstChild().getNodeValue());
System.out.println("================");
}
} catch (Exception e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
}
}


<?xml version="1.0" encoding="UTF-8"?>
<students>
<student>
<name id="001" xx="哈哈">张三</name>
<sex>男</sex>
<age>20</age>
</student>
<student>
<name id="002">李四</name>//studentname元素节点 id属性节点 文本节点 张三
<sex>女</sex>
<age>21</age>
</student>
</students>


//节点包括元素节点、属性节点、文本节点
元素一定是节点、但节点不一定是元素


XML部分
1、xml有哪些解析技术?区别是什么? 
答:有DOM,SAX,STAX等 
DOM:处理大型文件时其性能下降的非常厉害。这个问题是由DOM的树结构所造成的,这种结构占用的内存较多,而且DOM必须在解析文件之前把整个文档装入内存,适合对XML的随机访问SAX:不现于DOM,SAX是事件驱动型的XML解析方式。它顺序读取XML文件,不需要一次全部装载整个文件。当遇到像文件开头,文档结束,或者标签开头与标签结束时,它会触发一个事件,用户通过在其回调事件中写入处理代码来处理XML文件,适合对XML的顺序访问 
STAX:Streaming API for XML (StAX) 
讲解这些区别是不需要特别去比较,就像说传智播客与其他培训机构的区别时,我们只需说清楚传智播客有什么特点和优点就行了,这就已经间接回答了彼此的区别。


2、你在项目中用到了xml技术的哪些方面?如何实现的? 


答:用到了数据存贮,信息配置两方面。在做数据交换平台时,将不能数据源的数据组装成XML文件,然后将XML文件压缩打包加密后通过网络传送给接收者,接收解密与解压缩后再同XML文件中还原相关信息进行处理。在做软件配置时,利用XML可以很方便的进行,软件的各种配置参数都存贮在XML文件中。 


3、用jdom解析xml文件时如何解决中文问题?如何解析? 
答:看如下代码,用编码方式加以解决 
package test; 
import java.io.*; 
public class DOMTest 

private String inFile = "c:\\people.xml" 
private String outFile = "c:\\people.xml" 
public static void main(String args[]) 

new DOMTest(); 

public DOMTest() 

try 

javax.xml.parsers.DocumentBuilder builder = 
javax.xml.parsers.DocumentBuilderFactory.newInstance().newDocumentBuilder(); 
org.w3c.dom.Document doc = builder.newDocument(); 
org.w3c.dom.Element root = doc.createElement("老师"); 
org.w3c.dom.Element wang = doc.createElement("王"); 
org.w3c.dom.Element liu = doc.createElement("刘"); 
wang.appendChild(doc.createTextNode("我是王老师")); 
root.appendChild(wang); 
doc.appendChild(root); 
javax.xml.transform.Transformer transformer = 
javax.xml.transform.TransformerFactory.newInstance().newTransformer(); 
transformer.setOutputProperty(javax.xml.transform.OutputKeys.ENCODING, "gb2312"); 
transformer.setOutputProperty(javax.xml.transform.OutputKeys.INDENT, "yes"); 
transformer.transform(new javax.xml.transform.dom.DOMSource(doc), 
new 
javax.xml.transform.stream.StreamResult(outFile)); 

catch (Exception e) 

System.out.println (e.getMessage()); 


}


4、编程用JAVA解析XML的方式. 


答:用SAX方式解析XML,XML文件如下: 
<?xml version=1.0 encoding=gb2312?> 
<person> 
<name>王小明</name> 
<college>信息学院</college> 
<telephone>6258113</telephone> 
<notes>男,1955年生,博士,95年调入海南大学</notes> 
</person> 
事件回调类SAXHandler.java 
import java.io.*; 
import java.util.Hashtable; 
import org.xml.sax.*; 
public class SAXHandler extends HandlerBase 

private Hashtable table = new Hashtable(); 
private String currentElement = null; 
private String currentValue = null; 
public void setTable(Hashtable table) 

this.table = table; 

public Hashtable getTable() 

return table; 

public void startElement(String tag, AttributeList attrs) 
throws SAXException 

currentElement = tag; 

public void characters(char[] ch, int start, int length) 
throws SAXException 

currentValue = new String(ch, start, length); 

public void endElement(String name) throws SAXException 

if (currentElement.equals(name)) 
table.put(currentElement, currentValue); 




JSP内容显示源码,SaxXml.jsp: 
<HTML> 
<HEAD> 
<TITLE>剖析XML文件people.xml</TITLE> 
</HEAD> 
<BODY> 
<%@ page errorPage=ErrPage.jsp 
contentType=text/html;charset=GB2312 %> 
<%@ page import=java.io.* %> 
<%@ page import=java.util.Hashtable %> 
<%@ page import=org.w3c.dom.* %> 
<%@ page import=org.xml.sax.* %> 
<%@ page import=javax.xml.parsers.SAXParserFactory %> 
<%@ page import=javax.xml.parsers.SAXParser %> 
<%@ page import=SAXHandler %> 
<% 
File file = new File(c:\people.xml); 
FileReader reader = new FileReader(file); 
Parser parser; 
SAXParserFactory spf = SAXParserFactory.newInstance(); 
SAXParser sp = spf.newSAXParser(); 
SAXHandler handler = new SAXHandler(); 
sp.parse(new InputSource(reader), handler); 
Hashtable hashTable = handler.getTable(); 
out.println(<TABLE BORDER=2><CAPTION>教师信息表</CAPTION>); 
out.println(<TR><TD>姓名</TD> + <TD> + 
(String)hashTable.get(new String(name)) + </TD></TR>); 
out.println(<TR><TD>学院</TD> + <TD> + 
(String)hashTable.get(new String(college))+</TD></TR>); 
out.println(<TR><TD>电话</TD> + <TD> + 
(String)hashTable.get(new String(telephone)) + </TD></TR>); 
out.println(<TR><TD>备注</TD> + <TD> + 
(String)hashTable.get(new String(notes)) + </TD></TR>); 
out.println(</TABLE>); 
%> 
</BODY> 
</HTML> 


5、XML文档定义有几种形式?它们之间有何本质区别?解析XML文档有哪几种方式? 


a: 两种形式 dtd  schema,
b: 本质区别:schema本身是xml的,可以被XML解析器解析(这也是从DTD上发展schema的根本目的),c:有DOM,SAX,STAX等 
   DOM:处理大型文件时其性能下降的非常厉害。这个问题是由DOM的树结构所造成的,这种结构占用的内存较多,而且DOM必须在解析文件之前把整个文档装入内存,适合对XML的随机访问 SAX:不现于DOM,SAX是事件驱动型的XML解析方式。它顺序读取XML文件,不需要一次全部装载整个文件。当遇到像文件开头,文档结束,或者标签开头与标签结束时,它会触发一个事件,用户通过在其回调事件中写入处理代码来处理XML文件,适合对XML的顺序访问 STAX:Streaming API for XML (StAX)


SAX方式解析XML

SAX方式解析XML原理
SAX工作原理对文本进行顺序扫描,当扫描到文档开始于结束,元素开始于结束,文档结束等地方时通知事件处理函数,做出相应的动作,资源消耗小适合大文件。只能读取不能修改。


package com.java1234.xml;


import javax.xml.parsers.SAXParser;
import javax.xml.parsers.SAXParserFactory;


import org.xml.sax.Attributes;
import org.xml.sax.SAXException;
import org.xml.sax.helpers.DefaultHandler;


public class SAX01 extends DefaultHandler{//继承相当于句柄一样的东西


@Override
public void startDocument() throws SAXException {//文档开始事件
System.out.println("<?xml version=\"1.0\" encoding=\"UTF-8\"?>");
}


@Override
public void endDocument() throws SAXException {
System.out.print("\n 扫描文档结束");
}


@Override
public void startElement(String uri, String localName, String qName,
Attributes attributes) throws SAXException {//开始扫描元素的时候,元素是节点的子类
System.out.print("<");
System.out.print(qName);//打印整个xml  qNam就是studente
if(attributes!=null){//打印属性列表
for(int i=0;i<attributes.getLength();i++){
System.out.print(" "+attributes.getQName(i)+"=\""+attributes.getValue(i)+"\"");
}
}
System.out.print(">");
}


@Override
public void endElement(String uri, String localName, String qName)
throws SAXException {
System.out.print("</");
System.out.print(qName);
System.out.print(">");
}


@Override
public void characters(char[] ch, int start, int length)
throws SAXException {//文本节点
System.out.print(new String(ch,start,length));
}


public static void main(String[] args) throws Exception{
SAXParserFactory factory=SAXParserFactory.newInstance();//获取解析器
SAXParser parser=factory.newSAXParser();
parser.parse("src/student.xml", new SAX01());//扫描 url和实现类
}
}


package com.java1234.xml;


import java.util.ArrayList;
import java.util.List;


import javax.xml.parsers.SAXParser;
import javax.xml.parsers.SAXParserFactory;


import org.xml.sax.Attributes;
import org.xml.sax.SAXException;
import org.xml.sax.helpers.DefaultHandler;


import com.java1234.model.Student;


public class SAX02 extends DefaultHandler{
private List<Student> students=null;//放入学生的集合中在文档开始扫描的时候初始化
private Student student=null;//每次读取获取一个一个对象,存到集合中
private String preTag=null; // 标记上一个节点名称

@Override
public void startDocument() throws SAXException {
System.out.println("开始读取学生信息");
students=new ArrayList<Student>();
}


@Override
public void endDocument() throws SAXException {
System.out.println("\n 学生信息读取完毕");
}


@Override
public void startElement(String uri, String localName, String qName,
Attributes attributes) throws SAXException {
if("student".equals(qName)){
student=new Student();
student.setId(attributes.getValue(0));//获取ID
}
preTag=qName;
}


@Override
public void endElement(String uri, String localName, String qName)
throws SAXException {
if("student".equals(qName)){
students.add(student);//把student添加到集合中
student=null;
}
preTag=null;
}


@Override
public void characters(char[] ch, int start, int length)
throws SAXException {
if(preTag!=null){//标记用来判断记录前一个tag
String content=new String(ch,start,length);//获取节点值
if("name".equals(preTag)){
student.setName(content);
}else if("sex".equals(preTag)){
student.setSex(content);
}else if("age".equals(preTag)){
student.setAge(Integer.parseInt(content));
}
}
}


public static void main(String[] args) throws Exception{
SAXParserFactory factory=SAXParserFactory.newInstance();
SAXParser parser=factory.newSAXParser();
SAX02 sax02=new SAX02();
parser.parse("src/students.xml", sax02);
for(Student s:sax02.students){//list打印
System.out.println(s);
}
}
}


@Override
public String toString() {
// TODO Auto-generated method stub
return this.id+","+this.name+","+this.sex+","+this.age;
}


}


 Sax解析是按照xml文件的顺序一步一步的来解析,在解析xml文件之前,我们要先了解xml文件的节点的种类,一种是ElementNode,一种是TextNode。如下面的这段book.xml
xml文件被Sax解析器载入,由于Sax解析是按照xml文件的顺序来解析,当读入<?xml.....>时,会调用startDocument()方法,当读入<books>的时候,由于它是个ElementNode,所以会调用startElement(String uri, String localName, String qName, Attributes attributes) 方法,其中第二个参数就是节点的名称,注意:由于有些环境不一样,有时候第二个参数有可能为空,所以可以使用第三个参数,因此在解析前,先调用一下看哪个参数能用,第4个参数是这个节点的属性。这里我们不需要这个节点,所以从<book>这个节点开始,也就是图中1的位置,当读入时,调用startElement(....)方法,由于只有一个属性id,可以通过attributes.getValue(0)来得到,然后在图中标明2的地方会调用characters(char[] ch, int start, int length)方法,不要以为那里是空白,Sax解析器可不那么认为,Sax解析器会把它认为是一个TextNode。但是这个空白不是我们想要的数据,我们是想要<name>节点下的文本信息。这就要定义一个记录当上一节点的名称的TAG,在characters(.....)方法中,判断当前节点是不是name,是再取值,才能取到thinking in java。具体见代码:SaxParseService.java
import java.io.InputStream;  
import java.util.ArrayList;  
import java.util.List;  
  
import javax.xml.parsers.SAXParser;  
import javax.xml.parsers.SAXParserFactory;  
  
import org.xml.sax.Attributes;  
import org.xml.sax.SAXException;  
import org.xml.sax.helpers.DefaultHandler;  
  
import com.xtlh.cn.entity.Book;  
  
public class SaxParseService extends DefaultHandler{  
    private List<Book> books = null;  
    private Book book = null;  
    private String preTag = null;//作用是记录解析时的上一个节点名称  
      
    public List<Book> getBooks(InputStream xmlStream) throws Exception{  
        SAXParserFactory factory = SAXParserFactory.newInstance();  
        SAXParser parser = factory.newSAXParser();  
        SaxParseService handler = new SaxParseService();  
        parser.parse(xmlStream, handler);  
        return handler.getBooks();  
    }  
      
    public List<Book> getBooks(){  
        return books;  
    }  
      
    @Override  
    public void startDocument() throws SAXException {  
        books = new ArrayList<Book>();  
    }  
  
    @Override  
    public void startElement(String uri, String localName, String qName, Attributes attributes) throws SAXException {  
        if("book".equals(qName)){  
            book = new Book();  
            book.setId(Integer.parseInt(attributes.getValue(0)));  
        }  
        preTag = qName;//将正在解析的节点名称赋给preTag  
    }  
  
    @Override  
    public void endElement(String uri, String localName, String qName)  
            throws SAXException {  
        if("book".equals(qName)){  
            books.add(book);  
            book = null;  
        }  
        preTag = null;/**当解析结束时置为空。这里很重要,例如,当图中画3的位置结束后,会调用这个方法 
        ,如果这里不把preTag置为null,根据startElement(....)方法,preTag的值还是book,当文档顺序读到图 
        中标记4的位置时,会执行characters(char[] ch, int start, int length)这个方法,而characters(....)方 
        法判断preTag!=null,会执行if判断的代码,这样就会把空值赋值给book,这不是我们想要的。*/  
    }  
      
    @Override  
    public void characters(char[] ch, int start, int length) throws SAXException {  
        if(preTag!=null){  
            String content = new String(ch,start,length);  
            if("name".equals(preTag)){  
                book.setName(content);  
            }else if("price".equals(preTag)){  
                book.setPrice(Float.parseFloat(content));  
            }  
        }  
    }  
      
}  


测试是用的单元测试,测试代码如下:ParseTest


import java.io.InputStream;  
import java.util.List;  
  
import junit.framework.TestCase;  
  
import com.xtlh.cn.demo.DomParseService;  
import com.xtlh.cn.demo.SaxParseService;  
import com.xtlh.cn.entity.Book;  
  
public class ParseTest extends TestCase{  
  
    public void testSAX() throws Throwable{  
        SaxParseService sax = new SaxParseService();  
        InputStream input = this.getClass().getClassLoader().getResourceAsStream("book.xml");  
        List<Book> books = sax.getBooks(input);  
        for(Book book : books){  
            System.out.println(book.toString());  
        }  
    }  
}  























原创粉丝点击