您的位置:首页 > 编程语言 > Java开发

第7天(就业班) Dom4j修改xml、xPath技术、SAX解析

2017-01-08 08:55 369 查看
1 课程回顾

XML基础
1)XML的作用
1.1 作为软件配置文件
1.2 作为小型的“数据库”
2)XML语法(由w3c组织规定的)
标签:  
标签名不能以数字开头,中间不能有空格,区分大小写。有且仅有一个根标签。
属性:
可有多个属性,但属性值必须用引号(单引号或双引号)包含,但不能省略,也不能单、双混用。
文档声明:
<?xml version="1.0" encoding="utf-8"?>

encoding="utf-8": 打开或解析xml文档时的编码
注意:
保存xml文档时的编码 和 解析xml文档时的编码要保持一致,才能避免中文乱码问题!
3)XML解析
程序读取或操作xml文档
两种解析方式:   DOM解析   vs   SAX解析
DOM解析原理:一次性把xml文档加载成Document树,通过Document对象得到节点对象,通过节点对象访问xml文档内容(标签,属性,文本,注释)。
Dom4j工具(基于DOM解析原理):
读取xml文档:
   Document doc = new SAXReader().read("xml文件"); 
节点:
nodeIterator();  所有节点
标签:
element("名称")   指定名称的第一个子标签对象
elementIterator("名称");  指定名称的所有子标签对象
elements();  所有子标签对象
属性:
attributeValue(“名称”) 指定名称的属性值
attribute("名称")   指定名称的属性对象
getName()  属性名称
getValue()  属性值
atributeIterator()   所有属性对象(Iterator)
attributes()       所有属性对象(List)
文本:
getText()  得到当前标签的文本

elementText("子标签名称")  得到子标签的文本

2 Dom4j修改xml文档

       2.1 写出内容到xml文档

package gz.itcast.a_dom4j_write;

import java.io.File;
import java.io.FileOutputStream;

import org.dom4j.Document;
import org.dom4j.io.SAXReader;
import org.dom4j.io.XMLWriter;

/**
* 第一个写出内容到xml文档
* @author APPle
*
*/
public class Demo1 {

public static void main(String[] args) throws Exception{
//一、读取或创建一个Document对象
//读取day07项目的xm文件
Document doc = new SAXReader().read(new File("./src/contact.xml"));
//二、修改Document对象内容
//三、把修改后的Document对象写出到xml文档中
//指定文件输出的位置
FileOutputStream out = new FileOutputStream("e:/contact.xml");
//1.创建写出对象
XMLWriter writer = new XMLWriter(out);

//2.写出对象
writer.write(doc);
//3.关闭流
writer.close();
}
}
2.2 修改xml文档的API
增加:
DocumentHelper.createDocument()  增加文档
addElement("名称")  增加标签
addAttribute("名称",“值”)  增加属性
修改:
Attribute.setValue("值")  修改属性值
Element.addAtribute("同名的属性名","值")  修改同名的属性值
Element.setText("内容")  修改文本内容
删除
Element.detach();  删除标签
Attribute.detach();  删除属性

<?xml version="1.0" encoding="UTF-8"?>
<contactList>
<contact id="001" name="eric">
<name>张三</name>
<age>20</age>
<phone>134222223333</phone>
<email>zhangsan@qq.com</email>
<qq>432221111</qq>
</contact>
<contact id="002" name="jacky">
<name>eric</name>
<age>20</age>
<phone>134222225555</phone>
<email>lisi@qq.com</email>
<qq>432222222</qq>
</contact>
</contactList>package cn.xp.a_dom4j_write;
import java.io.File;
import java.io.FileOutputStream;

import org.dom4j.Document;
import org.dom4j.io.OutputFormat;
import org.dom4j.io.SAXReader;
import org.dom4j.io.XMLWriter;
/**
* 讨论写出内容到xml文档的细节
*/
public class Demo2 {
/**
* @param args
*/
public static void main(String[] args) throws Exception{
Document doc = new SAXReader().read(new File("./src/contact.xml"));
//指定文件输出的位置
FileOutputStream out = new FileOutputStream("e:/contact.xml");
/**
* 1.指定写出的格式
*/
OutputFormat format = OutputFormat.createCompactFormat(); //紧凑的格式.去除空格换行.项目上线的时候
//OutputFormat format = OutputFormat.createPrettyPrint(); //漂亮的格式.有空格和换行.开发调试的时候
/**
* 2.指定生成的xml文档的编码
*    同时影响了xml文档保存时的编码  和  xml文档声明的encoding的编码(xml解析时的编码)
*    结论: 使用该方法生成的xml文档避免中文乱码问题。
*/
format.setEncoding("utf-8");
//1.创建写出对象
XMLWriter writer = new XMLWriter(out,format);
//2.写出对象
writer.write(doc);
//3.关闭流
writer.close();
}
}

package cn.xp.a_dom4j_write;

package cn.xp.a_dom4j_write;

import org.dom4j.Attribute;
import org.dom4j.Document;
import org.dom4j.DocumentHelper;
import org.dom4j.Element;

import org.dom4j.io.OutputFormat;
import org.dom4j.io.SAXReader;
import org.dom4j.io.XMLWriter;

import org.junit.Test;

import java.io.File;
import java.io.FileOutputStream;

/**
* 修改xml内容
* 增加:文档,标签 ,属性
* 修改:属性值,文本
* 删除:标签,属性
* @author APPle
*
*/
public class Demo3 {
/**
* 增加:文档,标签 ,属性
*/
@Test
public void test1() throws Exception {
/**
* 1.创建文档
*/
Document doc = DocumentHelper.createDocument();

/**
* 2.增加标签
*/
Element rootElem = doc.addElement("contactList");

//doc.addElement("contactList");
Element contactElem = rootElem.addElement("contact");
contactElem.addElement("name");
/**
* 3.增加属性
*/
contactElem.addAttribute("id", "001");
contactElem.addAttribute("name", "eric");

//把修改后的Document对象写出到xml文档中
FileOutputStream out = new FileOutputStream("e:/contact.xml");
OutputFormat format = OutputFormat.createPrettyPrint();
format.setEncoding("utf-8");

XMLWriter writer = new XMLWriter(out, format);
writer.write(doc);
writer.close();
}

/**
* 修改:属性值,文本
* @throws Exception
*/
@Test
public void test2() throws Exception {
Document doc = new SAXReader().read(new File("./src/contact.xml"));

/**
* 方案一: 修改属性值   1.得到标签对象 2.得到属性对象 3.修改属性值
*/

//1.1  得到标签对象
/*
Element contactElem = doc.getRootElement().element("contact");
//1.2 得到属性对象
Attribute idAttr = contactElem.attribute("id");
//1.3 修改属性值
idAttr.setValue("003");
*/

/**
* 方案二: 修改属性值
*/

//1.1  得到标签对象
/*
Element contactElem = doc.getRootElement().element("contact");
//1.2 通过增加同名属性的方法,修改属性值
contactElem.addAttribute("id", "004");
*/

/**
* 修改文本 1.得到标签对象 2.修改文本
*/
Element nameElem = doc.getRootElement().element("contact")
.element("name");
nameElem.setText("李四");

FileOutputStream out = new FileOutputStream("e:/contact.xml");
OutputFormat format = OutputFormat.createPrettyPrint();
format.setEncoding("utf-8");

XMLWriter writer = new XMLWriter(out, format);
writer.write(doc);
writer.close();
}

/**
* 删除:标签,属性
* @throws Exception
*/
@Test
public void test3() throws Exception {
Document doc = new SAXReader().read(new File("./src/contact.xml"));
/**
* 1.删除标签     1.1 得到标签对象  1.2 删除标签对象
*/
// 1.1 得到标签对象
/*
Element ageElem = doc.getRootElement().element("contact")
.element("age");
//1.2 删除标签对象
ageElem.detach();
//ageElem.getParent().remove(ageElem);
*/
/**
* 2.删除属性   2.1得到属性对象  2.2 删除属性
*/
//2.1得到属性对象
//得到第二个contact标签
Element contactElem = (Element) doc.getRootElement().elements().get(1);

//2.2 得到属性对象
Attribute idAttr = contactElem.attribute("id");
//2.3 删除属性
idAttr.detach();

//idAttr.getParent().remove(idAttr);
FileOutputStream out = new FileOutputStream("e:/contact.xml");
OutputFormat format = OutputFormat.createPrettyPrint();
format.setEncoding("utf-8");

XMLWriter writer = new XMLWriter(out, format);
writer.write(doc);
writer.close();
}
}
3 xPath技术  
3.1 引入
问题:当使用dom4j查询比较深的层次结构的节点(标签,属性,文本),比较麻烦!!!
3.2 xPath作用
主要是用于快速获取所需的节点对象。
3.3 在dom4j中如何使用xPath技术
1)导入xPath支持jar包 。  jaxen-1.1-beta-6.jar
2)使用xpath方法
List<Node>  selectNodes("xpath表达式");   查询多个节点对象
Node       selectSingleNode("xpath表达式");  查询一个节点对象
package cn.xp.b_xpath;
import java.io.File;
import java.io.FileOutputStream;
import org.dom4j.Document;
import org.dom4j.Element;
import org.dom4j.io.OutputFormat;
import org.dom4j.io.SAXReader;
import org.dom4j.io.XMLWriter;
/**
* 第一个xpath程序
* @author APPle
*/
public class Demo1 {
public static void main(String[] args) throws Exception{
/**
* 需求: 删除id值为2的学生标签
*/
Document doc = new SAXReader().read(new File("e:/student.xml"));
//1.查询id为2的学生标签
//使用xpath技术
Element stuElem = (Element)doc.selectSingleNode("//Student[@id='2']");
//2.删除标签
stuElem.detach();
//3.写出xml文件
FileOutputStream out = new FileOutputStream("e:/student.xml");
OutputFormat format = OutputFormat.createPrettyPrint();
format.setEncoding("utf-8");
XMLWriter writer = new XMLWriter(out,format);
writer.write(doc);
writer.close();
}
}

    3.4 xPath语法

              /      绝对路径     表示从xml的根位置开始或子元素(一个层次结构)

              //     相对路径      表示不分任何层次结构的选择元素。

              *      通配符        表示匹配所有元素

              []      条件          表示选择什么条件下的元素

              @     属性           表示选择属性节点

              and     关系         表示条件的与关系(等价于&&)

              text()    文本          表示选择文本内容

package cn.xp.b_xpath;

import java.io.File;
import java.util.List;

import org.dom4j.Document;
import org.dom4j.Node;
import org.dom4j.io.SAXReader;
/**
* 学习xPath表达式语法
* @author APPle
*/
public class Demo2 {
public static void main(String[] args) throws Exception {
Document doc = new SAXReader().read(new File("./src/contact.xml"));
String xpath = "";
/**
* 1.  	/      绝对路径      表示从xml的根位置开始或子元素(一个层次结构)
*/
xpath = "/contactList";
xpath = "/contactList/contact";
/**
* 2. //     相对路径       表示不分任何层次结构的选择元素。
*/
xpath = "//contact/name";
xpath = "//name";

/**
* 3. *      通配符         表示匹配所有元素
*/
xpath = "/contactList/*"; //根标签contactList下的所有子标签
xpath = "/contactList//*";//根标签contactList下的所有标签(不分层次结构)
/**
* 4. []      条件           表示选择什么条件下的元素
*/
//带有id属性的contact标签
xpath = "//contact[@id]";
//第二个的contact标签
xpath = "//contact[2]";
//选择最后一个contact标签
xpath = "//contact[last()]";
/**
* 5. @     属性            表示选择属性节点
*/
xpath = "//@id"; //选择id属性节点对象,返回的是Attribute对象
xpath = "//contact[not(@id)]";//选择不包含id属性的contact标签节点
xpath = "//contact[@id='002']";//选择id属性值为002的contact标签
xpath = "//contact[@id='001' and @name='eric']";//选择id属性值为001,且name属性为eric的contact标签
/**
*6.  text()   表示选择文本内容
*/
//选择name标签下的文本内容,返回Text对象
xpath = "//name/text()";
xpath = "//contact/name[text()='张三']";//选择姓名为张三的name标签
List<Node> list = doc.selectNodes(xpath);
for (Node node : list) {
System.out.println(node);
}
}

}

 3.5 案例

              用户登录功能:

                  用户输入用户名和密码 -> 到“数据库”查询是否有对应的用户 ->

                     有: 则表示登录成功

                     没有: 则表示登录失败

package cn.xp.b_xpath;
import java.io.BufferedReader;
import java.io.File;
import java.io.InputStreamReader;

import org.dom4j.Document;
import org.dom4j.Element;
import org.dom4j.io.SAXReader;
/**
* xpath案例: 模拟用户登录效果
*/
public class Demo3 {
public static void main(String[] args)throws Exception{
//1.获取用户输入的用户名和密码
BufferedReader br =
new BufferedReader(new InputStreamReader(System.in));
System.out.println("请输入用户名:");
String name = br.readLine();
System.out.println("请输入密码:");
String password = br.readLine();
//2.到“数据库”中查询是否有对应的用户
//对应的用户:  在user.xml文件中找到一个
//name属性值为‘用户输入’,且password属性值为‘用户输入’的user标签
Document doc = new SAXReader().read(new File("./src/user.xml"));
Element userElem = (Element)doc.selectSingleNode("//user[@name='" +name +"' and @password='"+password+"']");
if(userElem!=null){
//登录成功
System.out.println("登录成功");
}else{
//登录失败
System.out.println("登录失败");
}
}
}
用xml当做数据库
user.xml   用来存储用户的数据
package cn.xp.b_xpath;

import org.dom4j.Document;
import org.dom4j.Element;

import org.dom4j.io.SAXReader;

import java.io.File;

import java.util.List;

/**
* 使用xpath技术读取一个规范的html文档
* @author APPle
*
*/
public class Demo4 {
public static void main(String[] args) throws Exception {
Document doc = new SAXReader().read(new File("./src/personList.html"));

//System.out.println(doc);
//读取title标签
Element titleElem = (Element) doc.selectSingleNode("//title");
String title = titleElem.getText();
System.out.println(title);

/**
* 练习:读取联系人的所有信息
* 按照以下格式输出:
*                  编号:001 姓名:张三 性别:男 年龄:18 地址:xxxx 电话: xxxx
*       编号:002 姓名:李四 性别:女 年龄:20 地址:xxxx 电话: xxxx
*       ......
*/

//1.读取出所有tbody中的tr标签
List<Element> list = (List<Element>) doc.selectNodes("//tbody/tr");

//2.遍历
for (Element elem : list) {
//编号
//String id = ((Element)elem.elements().get(0)).getText();
String id = elem.selectSingleNode("td[1]").getText();

//姓名
String name = ((Element) elem.elements().get(1)).getText();

//性别
String gender = ((Element) elem.elements().get(2)).getText();

//年龄
String age = ((Element) elem.elements().get(3)).getText();

//地址
String address = ((Element) elem.elements().get(4)).getText();

//电话
String phone = ((Element) elem.elements().get(5)).getText();

System.out.println("编号:" + id + "\t姓名:" + name + "\t性别:" + gender +
"\t年龄:" + age + "\t地址:" + address + "\t电话:" + phone);
}
}
}
<?xml version="1.0" encoding="utf-8"?>
<users>
<user id="001" name="eric" password="123456"></user>
<user id="002" name="rose" password="123456"></user>
<user id="003" name="jack" password="123456"></user>
</users>
4 SAX解析
4.1回顾DOM解析
DOM解析原理:一次性把xml文档加载进内存,然后在内存中构建Document树。
对内存要求比较要。

缺点: 不适合读取大容量的xml文件,容易导致内存溢出。

SAX解析原理: 加载一点,读取一点,处理一点。对内存要求比较低。
4.2 SAX解析工具

SAX解析工具-  Sun公司提供的。内置在jdk中。org.xml.sax.*
核心的API:
  SAXParser类: 用于读取和解析xml文件对象
parse(File f, DefaultHandler dh)方法: 解析xml文件
参数一: File:表示 读取的xml文件。
   参数二: DefaultHandler: SAX事件处理程序。使用DefaultHandler的子类

例如:{

      1.创建SAXParser对象  

              SAXParser parser=SAXParserFactory.newInstance().newSAXParser();

                  2.调用parse方法
parser.parse(new File("./src/contact.xml"), new MyDefaultHandler());

} [一个类继承class 类名(extends DefaultHandler)  在调用是创建传进去

DefaultHandler类的API:
void startDocument()  : 在读到文档开始时调用
void endDocument()  :在读到文档结束时调用
void startElement(String uri, String localName, String qName, Attributes attributes)  :读到开始标签时调用

void endElement(String uri, String localName, String qName)   :读到结束标签时调用
void characters(char[] ch, int start, int length)  : 读到文本内容时调用
package cn.xp.c_sax;

import java.io.File;

import javax.xml.parsers.SAXParser;
import javax.xml.parsers.SAXParserFactory;
/**
* 第一个SAX读取xml文件程序
*/
public class Demo1 {
public static void main(String[] args) throws Exception{
//1.创建SAXParser对象
SAXParser parser = SAXParserFactory.newInstance().newSAXParser();
//2.调用parse方法
/**
* 参数一: xml文档
* 参数二: DefaultHandler的子类
*/
parser.parse(new File("./src/contact.xml"), new MyDefaultHandler());
}
}
package cn.xp.c_sax;

import org.xml.sax.Attributes;
import org.xml.sax.SAXException;
import org.xml.sax.helpers.DefaultHandler;
/**
* SAX处理程序(如何解析xml文档)
*/
public class MyDefaultHandler extends DefaultHandler {

/**
* 开始文档时调用
*/
@Override
public void startDocument() throws SAXException {
System.out.println("MyDefaultHandler.startDocument()");
}

/**
* 开始标签时调用
* @param qName: 表示开始标签的标签名
* @param attributes: 表示开始标签内包含的属性列表
*/
@Override
public void startElement(String uri, String localName, String qName,
Attributes attributes) throws SAXException {
System.out.println("MyDefaultHandler.startElement()-->"+qName);
}
/**
* 结束标签时调用
* @param qName: 结束标签的标签名称
*/
@Override
public void endElement(String uri, String localName, String qName)
throws SAXException {
System.out.println("MyDefaultHandler.endElement()-->"+qName);
}
/**
* 读到文本内容的时调用
* @param ch: 表示当前读完的所有文本内容
* @param start: 表示当前文本内容的开始位置
* @param length: 表示当前文本内容的长度
* char[](                                       张三              20)   100
*                              98 2
*/
@Override
public void characters(char[] ch, int start, int length)
throws SAXException {
//得到当前文本内容
String content = new String(ch,start,length);
System.out.println("MyDefaultHandler.characters()-->"+content);
}

/**
* 结束文档时调用
*/
@Override
public void endDocument() throws SAXException {
System.out.println("MyDefaultHandler.endDocument()");
}

}

package cn.xp.c_sax;

import org.xml.sax.Attributes;
import org.xml.sax.SAXException;
import org.xml.sax.helpers.DefaultHandler;
/**
* SAX处理器程序
* @author APPle
*/
public class MyDefaultHandler2 extends DefaultHandler {
//存储xml文档信息
private StringBuffer sb = new StringBuffer();

//获取xml信息
public String getContent(){
return sb.toString();
}
/**
* 开始标签
*/
@Override
public void startElement(String uri, String localName, String qName,
Attributes attributes) throws SAXException {
sb.append("<"+qName);
//判断是否有属性
if(attributes!=null){
for(int i=0;i<attributes.getLength();i++){
//得到属性名称
String attrName = attributes.getQName(i);
//得到属性值
String attrValue = attributes.getValue(i);
sb.append(" "+attrName+"=\""+attrValue+"\"");
}
}
sb.append(">");
}
/**
* 文本内容
*/
@Override
public void characters(char[] ch, int start, int length)
throws SAXException {
//得到当前读取的文本
String content = new String(ch,start,length);
sb.append(content);
}
/**
* 结束标签
*/
@Override
public void endElement(String uri, String localName, String qName)
throws SAXException {
sb.append("</"+qName+">");
}
}
package cn.xp.c_sax;
import java.io.File;

import javax.xml.parsers.SAXParser;
import javax.xml.parsers.SAXParserFactory;
/**
* 读取contact.xml文件,完整输出文档内容
*/
public class Demo2 {
public static void main(String[] args)throws Exception {
//1.创建SAXParser
SAXParser parser = SAXParserFactory.newInstance().newSAXParser();
//2.读取xml文件
MyDefaultHandler2 handler = new MyDefaultHandler2();
parser.parse(new File("./src/contact.xml"), handler);
String content = handler.getContent();
System.out.println(content);
}
}

package cn.xp.c_sax;
import java.util.ArrayList;
import java.util.List;
import org.xml.sax.Attributes;
import org.xml.sax.SAXException;
import org.xml.sax.helpers.DefaultHandler;
/**
* SAX处理程序
*/
public class MyDefaultHandler3 extends DefaultHandler {
//存储所有联系人对象
private List<Contact> list = new ArrayList<Contact>();
public List<Contact> getList(){
return list;
}
//保存一个联系人信息
private Contact contact;
/**
* 思路:
* 	1)创建Contact对象
*  2)把每个contact标签内容存入到Contact对象
*  3)把Contact对象放入List中
*/
//用于临时存储当前读到的标签名
private String curTag;

@Override
public void startElement(String uri, String localName, String qName,
Attributes attributes) throws SAXException {
curTag = qName;
//读取到contact的开始标签创建Contact对象
if("contact".equals(qName)){
contact = new Contact();

//设置id值
contact.setId(attributes.getValue("id"));
}
}

@Override
public void characters(char[] ch, int start, int length)
throws SAXException {
//当前文本内容
String content = new String(ch,start,length);

if("name".equals(curTag)){
contact.setName(content);
}

if("age".equals(curTag)){
contact.setAge(content);
}

if("phone".equals(curTag)){
contact.setPhone(content);
}

if("email".equals(curTag)){
contact.setEmail(content);
}

if("qq".equals(curTag)){
contact.setQq(content);
}
}

@Override
public void endElement(String uri, String localName, String qName)
throws SAXException {
//设置空时为了避免空格换行设置到对象的属性中
curTag = null;
//读到contact的结束标签放入List中
if("contact".equals(qName)){
list.add(contact);
}
}
}
package cn.xp.c_sax;

import java.io.File;
import java.util.List;

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

/**
* 使用sax解析把 xml文档封装成对象
* @author APPle
*
*/
public class Demo3 {
public static void main(String[] args)throws Exception {
SAXParser parser = SAXParserFactory.newInstance().newSAXParser();
MyDefaultHandler3 handler = new MyDefaultHandler3();
parser.parse(new File("./src/contact.xml"), handler);
List<Contact> list = handler.getList();
for (Contact contact : list) {
System.out.println(contact);
}
}
}
package cn.xp.c_sax;

public class Contact {
private String id;
private String name;
private String age;
private String phone;
private String email;
private String qq;
public String getId() {
return id;
}
public void setId(String id) {
this.id = id;
}
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
public String getAge() {
return age;
}
public void setAge(String age) {
this.age = age;
}
public String getPhone() {
return phone;
}
public void setPhone(String phone) {
this.phone = phone;
}
public String getEmail() {
return email;
}
public void setEmail(String email) {
this.email = email;
}
public String getQq() {
return qq;
}
public void setQq(String qq) {
this.qq = qq;
}
@Override
public String toString() {
return "Contact [age=" + age + ", email=" + email + ", id=" + id
+ ", name=" + name + ", phone=" + phone + ", qq=" + qq + "]";
}

}

============DOM解析    vs   SAX解析		========

DOM解析	SAX解析
原理: 一次性加载xml文档,不适合大容量的文件读取	原理: 加载一点,读取一点,处理一点。适合大容量文件的读取
DOM解析可以任意进行增删改成	SAX解析只能读取
DOM解析任意读取任何位置的数据,甚至往回读	SAX解析只能从上往下,按顺序读取,不能往回读
DOM解析面向对象的编程方法(Node,Element,Attribute),Java开发者编码比较简单。	SAX解析基于事件的编程方法。java开发编码相对复杂。

总结:
1)Dom4j修改xml文档
new XMLWrier();
......
2)xPath技术: 快速查询xml节点
selectNodes()
selectSinglNode();
xpath表达式语言
3)  SAX解析
SAXParser parse
parser()
DefaultHandler类:
startElement();
characters();
endElement();
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息