xml基础及其解析xml文档
-
-
- xml基础及其解析xml文档
- xml基础语法
- 中国特色乱码问题
- 写xml文件的工具
- xml中使用的转义字符
- 处理指令已经过时
- xml的两个重要的功能
- xml注释
- xml解析Java应用程序读取xml文件的内容
- DOM4J使用
- DOM4J中核心API
- 将xml文档从磁盘读进内存形成Document对象
- 读取所有的标签节点
- 读取所有的属性节点
- 读取所有的文本节点
- 解决上面提出的问题
xml基础语法
一个基本的xml构成:
<?xml version="1.0" encoding="utf-8" ?>
<根节点>
<子节点>
</子节点>
</根节点>
注意:xml标签区分大小写,并且xml标签不能以数字开头,标签名中间不能使用空格,下面是几种错误的写法:
<2contach>
</2contach>
<contact list>
</contact list>
<Contact>
</contact>
中国特色乱码问题
首先出现乱码一定是由于编码与解码采用的标准不一样,我们能看到的中文等都属于字符,从字符变成字节的过程我们成为编码,从字节变成字符的过程我们称之为解码,对于chrome浏览器,默认使用的是utf-8编码进行解码,当然可以自己设置,但是由于我们的编写xml文件的工具不同,导致可能进行编码采用的不是utf-8,所以会出现编码与解码采用的码表是不一样的。
- 写完xml进行保存的时候(也就是将整个xml文件保存到硬盘中,保存到硬盘中要进行编码成为二进制的10格式),实际上也就是编码过程(保存时使用utf-8)
- 打开或者解析xml文件的时候,实际上也就是解码过程(解码时采用utf-8)
上述的两个地方应该保持一致才不会出现乱码。注意在Windows上默认的编码格式ANSI在中国的计算机平台上实际上就是GBK编码。
写xml文件的工具
- 记事本、EditPlus等 注意保存时使用utf-8编码
- MyEclipse 如果在MyEclipse工具开发xml文件,保存xml文件时会按照文档声明的encoding来保存xml文件
- workbench 一个开源的可视化xml生成器
注意:在打开修改xml文件时,要注意保存时的编码格式
xml中使用的转义字符
在xml文件中内置了一些特殊的字符,这些特殊字符不能直接被浏览器原样输出,如果希望把这些字符按照浏览器的原样输出,那么就需要使用转义字符来实现。
<?xml version="1.0" encoding="utf-8" ?>
<codes>
<code>
<p$gt; 段落 </p>
<code>
<![CDATA[ <html> <head> <title>这是一个xml文件</title> </head> <body> </body> </html> ]]>
</code>
</code>
</codes>
常用的特殊字符 转义字符
< < > >
'' "
& &
空格
处理指令–已经过时
处理指令的作用:告诉解析器怎样去解析该xml文档,用的最多的就是下面的一个申明,但是实际上也根本不用。
<?xml-stylesheet type="text/css" href="a.css" ?>
需要提取xml的内容,可以使用xml-stylesheet指令。
<?xml version="1.0" encoding="utf-8" ?>
<?xml-stylesheet type="text/css" href="" ?>
<codes>
<code>
<p$gt; 段落 </p>
<code>
<![CDATA[ <html> <head> <title>这是一个xml文件</title> </head> <body> </body> </html> ]]>
</code>
</code>
</codes>
我们引入css文件,改变默认抽取出来排放的规则。
<?xml version="1.0" encoding="utf-8" ?>
<?xml-stylesheet type="text/css" href="a.css" ?>
<contactlist>
<contect id="001">
<name>张三</name>
<telephone>120</telephone>
</contect>
<contect id="002">
<name>李四</name>
<telephone>110</telephone>
</contect>
</contactlist>
a.css
contect{ font-size:20px; font-color:red; width:100px; height:100px; display:block; margin-top:40px; background-color:green; }
上面的功能在xml中已经不再使用,但是xml仍然保留了这种功能,一般不会使用时,不要去刻意使用,如果要用到再去学就行了。
xml的两个重要的功能
下面两个作用在Java Web的开发中普遍使用
- 作为一个小型的数据库来保存数据,这相当于数据载体
- 作为软件的配置文件
xml注释
xml解析–Java应用程序读取xml文件的内容
xml文件除了给开发者看,但是更多的时候是使用程序去读取xml的内容,此时我们称为xml的解析。
xml解析原理
关于xml解析原理我们使用下面的xml代码进行使用和解析。
<?xml version="1.0" encoding="utf-8" ?>
<contactlist>
<contact id="001">
<name>张三</name>
<telephone>15338607192</telephone>
<age>20</age>
<email>zhangsan@qq.com</email>
<qq>13101900</qq>
</contact>
<contact id="002">
<name>李四</name>
<telephone>15338607193</telephone>
<age>20</age>
<email>lisi@qq.com</email>
<qq>13101901</qq>
</contact>
<contact id="003">
<name>王五</name>
<telephone>15338607194</telephone>
<age>21</age>
<email>wangwu@qq.com</email>
<qq>13101902</qq>
</contact>
</contactlist>
xml解析器在解析xml文档时,把xml文件的各个部分封装成对象,通过这些对象去操作xml文档,这个过程叫做DOM编程。解析的方式有且只有两种(从原理的角度上讲):
- DOM解析原理:xml解析器一次性将整个xml文档加载进内存,然后在内存中构建一棵Document对象树,通过Document对象可以得到树上的节点对象,通过节点对象就可以操作整个xml文档的内容。
在读取xml文档之后,会在内存中形成一棵DOM树,xml文件中的标签作为DOM树的节点,并且xml文档的根节点作为DOM树的根节点,所有的标签构成了一棵具有层次的树。节点存在一些信息:如节点名称、节点类型(标签节点、属性节点、文本节点、注释节点)。DOM解析是面向对象的编程。具体我们在使用时不用Node对象,而是使用其子类的三个对象。下面显示了DOM面向编程过程中常用的对象。
xml文档 —————-> Document对象 代表整个xml文档
节点 —————>Node对象 父类
标签节点 —————> Element对象 子类
属性节点 —————> Attribute对象 子类
文本节点 —————>Text对象 子类
那么我们怎么拿到这些对象信息呢?使用Document对象,它代表的是一个完整的xml文档,从而使得整个xml文档可以被读进去。
xml解析工具
工具是某种原理之下具体的实现方式,基于上面的两种解析方式,出现了很多的工具,大致分为下面几个:
DOM解析工具
- JAXP(Oracle官方的工具) 没人用,难用
- JDOM(非官方的民间组织开发的工具) 也较为难用
- DOM4J(JDOM组织出来一批人开发的) 最为流行,最好用 三个框架(SSH)默认都使用的是DOM4J去读取xml内容
- 其它解析工具,不入流,不讨论
SAX解析工具
- Sax解析工具 (Oracle官方提供的解析工具)
DOM4J使用
DOM4J是基于DOM解析原理实现的xml文档解析工具,不包含在我们官方的JDK中,所以我们在使用的时候很关键的一点就是导包,导包,并且将其源码实现关联,以方便我们查看源代码,另外还有需要注意的是:使用第三方工具千万不能导错包,导包时要注意看清楚。
contact.xml
<?xml version="1.0" encoding="utf-8" ?>
<contactlist>
<contact id="001">
<name>张三</name>
<telephone>15338607192</telephone>
<age>20</age>
<email>zhangsan@qq.com</email>
<qq>13101900</qq>
</contact>
<contact id="002">
<name>李四</name>
<telephone>15338607193</telephone>
<age>20</age>
<email>lisi@qq.com</email>
<qq>13101901</qq>
</contact>
<contact id="003">
<name>王五</name>
<telephone>15338607194</telephone>
<age>21</age>
<email>wangwu@qq.com</email>
<qq>13101902</qq>
</contact>
</contactlist>
DOM4J中核心API
- Element.getText(); //获取当前指定标签下的文本内容
- Element.elementText(“标签名”);//获取指定标签的文本内容
将xml文档从磁盘读进内存,形成Document对象
testParseXml.java
package com.jpzhutech.xml;
import java.io.File;
import org.dom4j.Document;
import org.dom4j.DocumentException;
import org.dom4j.io.SAXReader;
import org.junit.Test;
public class ParseXml {
@Test
public void testParseXml(){
SAXReader reader = new SAXReader();
try {
Document document = reader.read(new File("./src/contact.xml"));
System.out.println(document);
} catch (DocumentException e) {
throw new RuntimeException(e);
}
}
}
读取所有的标签节点
将磁盘中的xml文档读进内存形成Document对象之后,此时我们就可以读取其中的标签、属性、文本等的内容了。
* 拿到所有的标签节点(Element) 使用nodeIterator方法进行循环迭代就能一层层的取出其中的标签节点
readXmlContext.java
package com.jpzhutech.xml;
import java.io.File;
import java.util.Iterator;
import org.dom4j.Branch;
import org.dom4j.Document;
import org.dom4j.DocumentException;
import org.dom4j.Element;
import org.dom4j.Node;
import org.dom4j.io.SAXReader;
import org.junit.Test;
public class readXmlContext {
@Test
public void test1(){
SAXReader reader = new SAXReader();
try {
Document document = reader.read(new File("./src/contact.xml"));
Iterator<Node> nodeIterator = document.nodeIterator();
while(nodeIterator.hasNext()){
Node node = nodeIterator.next();
String name = node.getName();
System.out.println(name);
if(node instanceof Element){
Element element = (Element) node;
Iterator<Node> nodeIterator2 = element.nodeIterator();
while(nodeIterator2.hasNext()){
Node next = nodeIterator2.next();
String name2 = next.getName();
System.out.println(name2);
if(next instanceof Element){
Element element2 = (Element)next;
Iterator<Node> nodeIterator3 = element2.nodeIterator();
while(nodeIterator3.hasNext()){
Node next2 = nodeIterator3.next();
String name3 = next2.getName();
System.out.println(name3);
}
}
}
}
}
} catch (DocumentException e) {
throw new RuntimeException(e);
}
}
}
稍微对上面的方法进行了改造,在获取其中的根标签时使用了getRootElement(),而不是把根标签当做一个普通的标签
package com.jpzhutech.xml;
import java.io.File;
import java.util.Iterator;
import org.dom4j.Branch;
import org.dom4j.Document;
import org.dom4j.DocumentException;
import org.dom4j.Element;
import org.dom4j.Node;
import org.dom4j.io.SAXReader;
import org.junit.Test;
public class readXmlContext {
@Test
public void test1(){
SAXReader reader = new SAXReader();
try {
Document document = reader.read(new File("./src/contact.xml"));
Iterator<Node> nodeIterator = document.nodeIterator();
while(nodeIterator.hasNext()){
Node node = nodeIterator.next();
String name = node.getName();
System.out.println(name);
if(node instanceof Element){
Element element = (Element) node;
Iterator<Node> nodeIterator2 = element.nodeIterator();
while(nodeIterator2.hasNext()){
Node next = nodeIterator2.next();
String name2 = next.getName();
System.out.println(name2);
if(next instanceof Element){
Element element2 = (Element)next;
Iterator<Node> nodeIterator3 = element2.nodeIterator();
while(nodeIterator3.hasNext()){
Node next2 = nodeIterator3.next();
String name3 = next2.getName();
System.out.println(name3);
}
}
}
}
}
} catch (DocumentException e) {
throw new RuntimeException(e);
}
}
@Test
public void test2(){
SAXReader reader = new SAXReader();
try {
Document document = reader.read(new File("./src/contact.xml"));
Element rootElement = document.getRootElement();
getChildNodes(rootElement);
} catch (DocumentException e) {
throw new RuntimeException(e);
}
}
public void getChildNodes(Element element){
System.out.println(element.getName());
Iterator<Node> nodeIterator = element.nodeIterator();
while(nodeIterator.hasNext()){
Node next = nodeIterator.next();
String name = next.getName();
System.out.println(name);
if(next instanceof Element){
Element element2 = (Element)next;
getChildNodes(element2);
}
}
}
}
package com.jpzhutech.xml;
import java.io.File;
import java.util.Iterator;
import java.util.List;
import org.dom4j.Branch;
import org.dom4j.Document;
import org.dom4j.DocumentException;
import org.dom4j.Element;
import org.dom4j.Node;
import org.dom4j.io.SAXReader;
import org.junit.Test;
public class readXmlContext {
@Test
public void test1(){
SAXReader reader = new SAXReader();
try {
Document document = reader.read(new File("./src/contact.xml"));
Iterator<Node> nodeIterator = document.nodeIterator();
while(nodeIterator.hasNext()){
Node node = nodeIterator.next();
String name = node.getName();
System.out.println(name);
if(node instanceof Element){
Element element = (Element) node;
Iterator<Node> nodeIterator2 = element.nodeIterator();
while(nodeIterator2.hasNext()){
Node next = nodeIterator2.next();
String name2 = next.getName();
System.out.println(name2);
if(next instanceof Element){
Element element2 = (Element)next;
Iterator<Node> nodeIterator3 = element2.nodeIterator();
while(nodeIterator3.hasNext()){
Node next2 = nodeIterator3.next();
String name3 = next2.getName();
System.out.println(name3);
}
}
}
}
}
} catch (DocumentException e) {
throw new RuntimeException(e);
}
}
@Test
public void test2(){
SAXReader reader = new SAXReader();
try {
Document document = reader.read(new File("./src/contact.xml"));
Element rootElement = document.getRootElement();
getChildNodes(rootElement);
} catch (DocumentException e) {
throw new RuntimeException(e);
}
}
public void getChildNodes(Element element){
System.out.println(element.getName());
Iterator<Node> nodeIterator = element.nodeIterator();
while(nodeIterator.hasNext()){
Node next = nodeIterator.next();
String name = next.getName();
System.out.println(name);
if(next instanceof Element){
Element element2 = (Element)next;
getChildNodes(element2);
}
}
}
@Test
public void test3(){
SAXReader reader = new SAXReader();
Document document;
try {
document = reader.read(new File("./src/contact.xml"));
Element element = document.getRootElement().element("contact").element("name");
System.out.println(element.getName())s;
} catch (DocumentException e) {
throw new RuntimeException(e);
}
}
}
在输出中出现了很多的null,这是为什么呢?在后面获取文本标签时会说明原因。
读取所有的属性节点
@Test
public void test4(){
SAXReader reader = new SAXReader();
try {
Document document = reader.read(new File("./src/contact.xml"));
Element element = document.getRootElement().element("contact");
} catch (DocumentException e) {
throw new RuntimeException(e);
}
}
读取所有的文本节点
@Test
public void test5(){
SAXReader reader = new SAXReader();
try {
Document document = reader.read("./src/contact.xml");
String elementText = document.getRootElement().element("contact").elementText("telephone");
System.out.println(elementText);
} catch (DocumentException e) {
throw new RuntimeException(e);
}
}
解决上面提出的问题
实际上在xml文档中空格、换行都是算xml文档的内容,不能忽略掉,也就是说在读取的时候,如果空格、换行出现了,那么我们应该将其中的内容读出。