1,回顾:
Html的时候说过,对标记型文档的解析有DOM技术和SAX技术两种,
而xml也是标记型文档,所以它的解析方式也是这两种:
1> DOM技术解析XML同样是先将整个XML文档加载到内存中,根据再
标签间的层次结构,将XML文档解析成树状结构,并树状在结构中
把XML文档的每个标签,属性,文本都封装成了节点对象,通进而
过操作不同的节点对象来操作XML文件。
DOM解析的优点:将XML文档的所有标签,属性,文本都封装成了对象,
可以很方便的对XML文档进行增,删,改,查操作。
DOM解析的缺点:首先要将整个XML文档完全的加载到内存中,耗时会
耗内存,如果文件过大时还会造成内存溢出。
2> SAX技术解析XML,采用事件驱动,边读边解析。即从上到下,一行
一行的解析,解析到某一个对象就把该对象返回。
SAX解析的优点:因为对文档是从上到下一行一行的解析,所以造不会
分类中翻译内存溢出。
SAX解析的缺点:也正是因为对文档是从上到下一行一行的解析,解析
到某一对象就报道查看该对象,所以SAX技术只能实现查询操作,不能实现
增,删,改操作,因为无法读取到整体的文档结构。
2,XML解析器:
。了解了XML的两种解析方式,接下来就是实现对XML文档的解析那么想
。要解析XML文档,首先就需要解析器而不同的公司和组织针对DOM和SAX
方式, 。提供了不同的解析器常用的有:
1> sun公司提供的jaxp解析器
2> jdom组织提供的jdom解析器
3> dom4j组织提供的dom4j解析器
在这三种解析器中我们只学习JAXP和dom4j中的使用,首先学习JAXP原因的
的英文因为它的英文由太阳公司提供的,JAVA就是由太阳公司开发的,而JAXP解析
器对XML的解析提供了标准。而学习的dom4j的原因是DOM4J和JDOM原来的英文一
家公司,dom4j的公司是后期从JDOM公司中分离出去的,dom4j的是在JDOM的
基础上进行了功能扩展,可以说是及JDOM的优点于一身,而功能比JDOM
更加强大完善。而在实际开发中解析XML使用的最多的还是dom4j的解析器。
3,jaxp解析器:
jaxp开发包是由sun公司提供,它其实是JAVASE的一部分,所以可在
JAVA_JDK_API进行查阅。
首先我们先了解几个常用类,这些类在javax.xml.parsers中的包中。可以
通过使用这些类,得到对XML文档进行解析的DOM解析器对象和SAX解析
器对象。
1,针对dom方式:
DocumentBuilder:DOM解析器类
DocumentBuilderFactory:DOM解析器工厂类
DocumentBuilder对象的常用方法parse方法:
Document | parse(File f) 将给定文件的内容解析为一个XML文档,
并且返回一个新的 DOM Document 对象。
Document | parse(InputStream is) 将给定 InputStream 的内容解析
为一个 XML 文档,并且返回一个新的 DOM Document 对象。
Document | parse(String uri) 将给定 URI 的内容解析为一个XML文档,
并且返回一个新的 DOM Document 对象。
Document接口的常用方法:
Element | getElementById(String elementId) 通过id属性
获取节点对象;
NodeList | getElementsByTagName(String tagname)通过
标签名获取节点对象。返回的是个集合NodeList。
Element | createElement(String tagName) 创建标签节点
Text | createTextNode(String data) 创建文本节点
父接口Node中方法:
Node | appendChild(Node newChild) 将参数节点添加到当前节点的子
节点列表的末尾
Node | removeChild(Node oldChild) 将参数子节点删除
Node | getParentNode() 获取当前节点的父节点
Node | getFirstChild() 获取当前节点的第一个子节点
Node | getLastChild() 获取当前节点的最后一个子节点
Node | cloneNode(boolean deep) 复制节点
String | getTextContent() 以字符串形式返回标签封装的内容。
void | setTextContent("值") 修改当前节点的文本内容
注意:
1.Document接口、Element接口、Text接口都是Node接口的子接口。
注意各个方法中的多态思想。
2.使用getElementsByTagName(String tagname)通过
标签名获取节点对象。返回的是个集合NodeList。遍历NodeList集合:
在NodeList集合中有:
int | getLength() 集合中的节点数
Node | item(int index) 返回集合中的第 index 个节点。
如:
NodeList nl = document.getElementsByTagName("a");
for(int i=0;i<nl.getLength();i++){
nl.item(i);
}
回写xml:
通过操作document对象和其它节点对象实现更新xml文档时,注意这里所谓
的更新,实际更新的是加载进内存中的xml文档。而想达到更新实际的xml
文档还得进行回写操作。
回写xml文件要使用javax.xml.transform包下的Transformer类的对象(此
抽象类的实例能够将源树转换为结果树),但是Transformer类是个抽象类不
能实例化,所以使用TransformerFactory类的对象的newTransformer()方法。
TransformerFactory类也是个抽象也不能实例化,所以使用其静态方法
newInstance()方法来创建
TransformerFactory类的对象。
得到Transformer对象后,使用Transformer对象的transform()方法实现回
写,而transform()方法有两个参数
参数1是:Source对象,表示源对象,而Source又是个接口不能实例化,所以
使用其实现类的对象,而Source的实现类有多个,因为是DOM方式进行解析,
所以使用DOMSource实现类的对象。
常用的是参数是Node对象的构造器来创建DOMSource对象,因为Document接
口是Node接口的子接口,所以构造器直接传document对象为参数即可。
参数2是:Result对象,表示目标对象,Result也是接口不能实例化,所以使用
其实现类的对象,而Result的实现类也有多个,因为对文件的操作一般使用
IO流,所以使用StreamResult实现类的对象。常用的是参数是文件的字符串
路径的构造器来创建StreamResult对象,所以构造器直接传xml文件的字符
串路径
创建StreamResult对象即可。
TransformerFactory tff = TransformerFactory.newInstance();
Transformer tf = tff.newTransformer();
tf.transform(newDOMSource(document),
new StreamResult("url"));
2、针对sax方式:
SAXParser:SAX解析器类
SAXParserFactory:SAX解析器工厂类
通过API看到SAXParser类是个抽象类,不能实例化对象,是通过SAXParserFactory
类的对象的newSAXParser()方法获取SAXParser类的对象的。
而通过API看到SAXParserFactory类也是个抽象类,也不能实例化,是通过
调用其静态方法newInstance()获取SAXParserFactory类的对象的。
再看一下解析器类SAXParser的对象的常用方法:
parse(File f, DefaultHandler dh) 使用指定的 DefaultHandler 将指定
文件的内容解析为 XML。
parse(InputStream is, DefaultHandler dh) 使用指定的 DefaultHandler
将给定的 InputStream 实例的内容解析为 XML。
parse(String uri, DefaultHandler dh) 使用指定的 DefaultHandler 将
给定统一资源标识符 (URI) 描述的内容解析为 XML。
我们看到SAX解析器解析xml文档的parse()方法有两个参
数。参数一是xml文档;参数二是事件处理器DefaultHandler,因为SAX解析技
术是基于事件驱动的方式对xml文档进行解析的。
看API在事件处理器DefaultHandler中常用方法就只有3
个:
startElement(String uri, String localName, String qName, Attributes attributes)
接收开始标签。
characters(char[] ch, int start, int length)
接收标签中封装的字符数据。
endElement(String uri, String localName, String qName)
接收结束标签。
调用parse()方法解析xml文档需要传递两个参数。参数一是xml文档;参数二
是事件处理器DefaultHandler,当把事件处理器传递进来,就相当于将事件处
理器绑定在了xml文档上。Parse()方法被调用,事件处理器将自动执行。xml
文档从上往下一行一行被解析,当解析到开始标签会自动驱动执行事件处理器
的startElement()方法,startElement()方法的参数qName返回开始标签名称;
当解析到文本会自动驱动执行事件处理器的characters()方法,characters()
方法中使用字符串的String(char[] ch,int start,int length)构造器返回文
本内容;当解析到结束标签会自动驱动执行事件处理器的endElement()方法,
endElement()方法的参数qName返回结束标签的名称。
使用jaxp的SAX方式解析xml文档,SAX方式只能实现查询操作,不能实现增删改操作
dom4j技术介绍:
dom4j是一个组织,针对xml的解析它提供了解析器dom4j。dom4j的前身是jdom,
它在jdom的基础上进行了功能扩展,比jdom功能更加强大,基于jdom的优点于
一身。所以目前实际开发中解析xml使用最多的还是dom4j。
但是dom4j它不是JavaSe的一部分,属于第三方开发包,所以想要使用dom4j第
一步必须导入dom4j的开发jar包。---->dom4j-1.6.1.jar (1.6版本的)
dom4j解析xml:
1. SAXReader解析器类:
SAXReader creates a DOM4J tree from SAX parsing events, 意思
SAXReader通过SAX解析创建一个dom4j树。
dom4j的底层是通过SAX方式解析出整个xml文档,再将整个xml文档生成DOM树,
进而可以进行增删改查操作。所以叫SAXReader。这就说明dom4j和jaxp是不一
样的,它不分DOM方式和SAX方式,而是与DOM方式和SAX方式为一体的。
2.创建解析器对象,获取Document对象:
先得使用SAXReader类默认无参的构造器创建解析器,然后再使用解析器的
read()方法解析xml文档,返回的Document对象就代表xml文档:
SAXReader reader = new SAXReader();
Document document = reader.read(url);
3. read方法:
Document | read(InputStream in)
Document | read(File file)
Document | read(String url)
4. Document是个接口,父接口是Node
再看Node接口,Document、Element、Text都是它的子接口。
5.常用方法:
1>Document的常用方法:
Element | getRootElement() 获取根节点,返回值是Element对象,就代表根节点。
2>Element的常用方法:
1)Element | element(String name) 获取当前标签下的第一个参数名称子
标签(注意是直接子标签),参数是子标签名,返回值是Element
2)List | elements(String name) 获取当前标签下的所有参数名称子标签
(注意是直接子标签),参数是子标签名,返回值是List。
3)List | elements() 获取当前标签下的所有子标签(注意是直接子标签),
返回值是List集合。
4)Element | addElement(String name) 给当前标签添加参数名称子标签,
返回值是Element代表添加的子标签。
(这个方法是其父接口Branch的方法)
5)String | getText() 获取当前标签的文本内容,返回值是String
6)void | setText(String content) 给当前标签添加文本或修改当前标签
的文本内容,参数就是添加的文本内容或修改后的文本内容。
(这个方法是其父接口Node的方法)
7)Element | getParent() 获取当前节点的父节点,返回值Element对象就
代表当前节点的父节点。
(这个方法是其父接口Node的方法)
8)boolean | remove(Element) 删除当前标签的参数子标签,参数Element
对象就是被删除的子节点对象。
(这个方法是其父接口Branch的方法)
9)String | attributeValue(String name)获取当前标签的参数名称属性值。
10)Element | addAttribute(String name,String value)给当前标签添加
属性或修改当前标签的属性,参数一是属性名称,参数二是属性值,返回值
是当前标签。
11)Attribute | attribute(String name)获取当前标签的参数名称属性并
将属性封装成Attribute对象。(是Node接口的子接口)
12)boolean | remove(Attribute)删除当前标签的参数Attribute对象属性,
参数就是代表被删除的属性的Attribute对象。
6. xml的回写:
1>XMLWriter xml写入器
XMLWriter类的构造器很多,而一般使用的是XMLWriter(OutputStream out, OutputFormat format)
构造器来创建XMLWriter对象。此构造器的有两个参数,参数一是OutputStream
字节输出流的对象,也就是说xml写入器的底层是通过流去写入的;参数二是
OutputFormat对象。
2>OutputFormat---> 输出格式器--->用于指定写入到xml文档的格式。
OutputFormat也是个一般类,但是不使用其构造器来创建对象,而是使OutputFormat
类的两个静态方法来创建输出格式器OutputFormat的对象:
static OutputFormat | createCompactFormat()创建一个带有压实格式的
输出格式器对象(压实格式指在一行,没有空格,没有换行)。
static OutputFormat | createPrettyPrint()创建一个漂亮格式的输出格
式器对象(漂亮格式就是指xml文档的格式,有缩进层次关系)<一般就用此方法>
3>XMLWriter的常用方法:
write(Doument document) 写入xml文档,参数是Document对象
close() 关闭写入器
setEncoding(String encoding)设置写入xml的编码格式,只要保证和xml
文档的编码格式一致就不会出现乱码问题。
XPath技术介绍:
使用dom4j操作xml文档,因为dom4j的底层是通过SAX方式对xml文档进行
解析的,然后再将整个xml文档生成DOM树。所以想要获取到某个标签并对
其进行操作,必须从上往下依次拿到根节点、下一节点、再下一节点……直
到拿到我们所需的节点,这样做的话,如果xml文档的层次关系很复杂的
话是不是很麻烦。所以dom4j又提供了XPath技术,其作用就是可以直接获
取到指定元素。本质就是通过标签间的层次关系表达式获取想要的指定元
素。
打开XPath的帮助文档XPath Tutorial,选择General_chi/examples.html (中文),
XPath的常用的表达式:
实例1---->第一种表达式:
/AAA 表示根元素AAA标签
/AAA/CCC 表示根元素AAA下的所有CCC子标签
/AAA/DDD/BBB 表示根元素AAA下的所有DDD子标签下的所有BBB子标签
实例2---->第二种表达式:
//BBB 表示所有BBB标签
//DDD/BBB 表示所有父元素是DDD的所有BBB标签
实例3---->第三种表达式:
/AAA/CCC/DDD/* 表示根元素AAA下的所有CCC子标签下的所有DDD子标签的
所有标签
/*/*/*/BBB表示所有的有3个祖先元素的BBB元素
//*表示所有的标签
实例4---->第四种表达式:
/AAA/BBB[1]表示根标签AAA下的第一个BBB子元素
/AAA/BBB[last()]表示根标签AAA下的最后一个BBB子元素
实例5---->第五种表达式:
//@id表示所有的id属性
//BBB[@id]表示所有具有id属性的BBB元素
//BBB[@name]表示所有具有name属性的BBB元素
//BBB[@*]表示具有任意属性的BBB元素
//BBB[not(@*)]表示没有属性的BBB元素
实例6 ---->第六种表达式:
// BBB [@ id ='b1']表示所有id属性值是b1的BBB元素
// BBB [@ name ='bbb']表示所有name属性值是BBB的BBB元素
四,使用XPath的技术:
默认情况下DOM4J不支持的XPath技术,如果想要通过DOM4J使用XPath的技术,
必须先导入的XPath的开发罐包.jaxen-1.1-β-6.jar。
dom4j提供了Document的两个方法用来支持XPath技术:
1> selectNodes(“XPath表达式”)--->获取多个元素,返回值是List集合,
泛型是Node.2
> selectSingleNode(“XPath”表达式“)--->获取单个元素,返回值是节点
对象就代表的XPath表达式所表示的标签。