解析方式 | 简介 | 优点 | 缺点 |
---|---|---|---|
DOM | Document Object Model文档对象模型,把整个XML文档先加载到内存中,形成树状结构 | 节点与节点之间有关系,进行增删改非常方便 | 如果文档非常大,加载到内存中容易产生内存溢出的问题 |
SAX | Simple API for XML 基于事件驱动的,边读边解析 | 文档大也不会有内存溢出的问题,查找非常方便 | 不能进行增删改的操作 |
解析开发包 | 简介 |
---|---|
JAXP | javaSE的一部分,想做增删改,只能用DOM方式。如果SAx,只能做查询 |
Dom4j | 企业都在用,DOM4J提供。增删改查都可以做 |
JAXP解析
解析方式 | 解析器工厂类 | 解析器对象 |
---|---|---|
DOM | DocumentBuilderFactory | DocumentBuilder |
SAX | SAXParserFactory | SAXParser |
JAXP的DOM解析
- 由解析器工厂类获取解析器工厂
- 解析器工厂产生一个解析器
- 解析XML,获得一个Document对象。Document parse(String uri)
- 回写
a 获取回写的工厂类TransformerFactory
b 获取回写类transformer
c transform(new DOMSource(document), new StreamResult("src/book2.xml"));
//获取作者的文本内容
public static void run1() throws ParserConfigurationException, SAXException, IOException{
//获取解析器工厂类
DocumentBuilderFactory factory = DocumentBuilderFactory.newInstance();
//获取解析器对象
DocumentBuilder builder = factory.newDocumentBuilder();
//解析XML的文档,返回document对象
Document document = builder.parse("src/book2.xml");
//获取作者元素对象的集合,返回NodeList
NodeList nodelist = document.getElementsByTagName("作者");
//循环遍历,获得每一个作者,打印文本的内容
for(int i = 0; i < nodelist.getLength(); i++){
Node node = nodelist.item(i);
System.out.println(node.getTextContent());
}
}
//在第二本下,在末尾添加子节点,需要回写类
public static void run2() throws Exception{
//获取工厂类
DocumentBuilderFactory factory = DocumentBuilderFactory.newInstance();
//获取解析类
DocumentBuilder builder = factory.newDocumentBuilder();
//解析XML,返回Document对象
Document document = builder.parse("src/book2.xml");
//获取第二本书
Node book2 = document.getElementsByTagName("书").item(1);
//创建元素对象
Element cat = document.createElement("毛");
//设置文本内容
cat.setTextContent("我是猫");
//把元素对象添加到第二本书下
book2.appendChild(cat);
//回写
//创建回写类的工厂
TransformerFactory transFactory = TransformerFactory.newInstance();
//获取回写类
Transformer transformer = transFactory.newTransformer();
//调用回写的方法
transformer.transform(new DOMSource(document), new StreamResult("src/book2.xml"));
}
/**
* 获取第一本书的属性值
* @throws Exception
*/
public static void run3() throws Exception{
//获取工厂类
DocumentBuilderFactory factory = DocumentBuilderFactory.newInstance();
//解析器
DocumentBuilder builder = factory.newDocumentBuilder();
//解析
Document document = builder.parse("src/book2.xml");
//获取作者,再获取第二本书
Node book1 = document.getElementsByTagName("书").item(0);
//乡下转型
Element book = (Element)book1;
System.out.println(book.getAttribute("编号"));
}
/**
* 在作者标签之前,添加团购价标签
* @throws Exception
*/
public static void run1() throws Exception{
//获取工厂类
DocumentBuilderFactory factory = DocumentBuilderFactory.newInstance();
//解析器
DocumentBuilder builder = factory.newDocumentBuilder();
//解析
Document document = builder.parse("src/book2.xml");
//获取作者,再获取第二本书
Node author = document.getElementsByTagName("作者").item(1);
Node book2 = author.getParentNode();
//创建元素
Element tuan = document.createElement("团购价");
//设置文本
tuan.setTextContent("很便宜");
//加入到作者之前
book2.insertBefore(tuan, author);
//回写
TransformerFactory factory2 = TransformerFactory.newInstance();
Transformer transformer = factory2.newTransformer();
transformer.transform(new DOMSource(document), new StreamResult("src/book2.xml"));
}
JAXP 的 DOM 封装
public class JaxpDomUtil {
/**
* 通过path获取document对象
* @throws Exception
*/
public static Document getDocument(String path) throws Exception{
//获取工厂类
DocumentBuilderFactory factory = DocumentBuilderFactory.newInstance();
//获取解析器对象
DocumentBuilder builder = factory.newDocumentBuilder();
//解析XML
Document document = builder.parse(path);
return document;
}
public static void writeXML(Document document,String path) throws Exception{
//获得回写类工厂
TransformerFactory factory = TransformerFactory.newInstance();
//获得回写类
Transformer transformer = factory.newTransformer();
//回写
transformer.transform(new DOMSource(document), new StreamResult(path));
}
public static void delete() throws Exception{
//获取文档对象
Document document = getDocument("src/book2.xml");
//获取猫
Node cat = document.getElementsByTagName("毛").item(0);
//获取书(猫的父节点)
Node book = cat.getParentNode();
//通过书删除猫
book.removeChild(cat);
//回写
writeXML(document,"src/boo2.xml");
}
public static void main(String[] args) throws Exception {
delete();
}
}
JAXP的SAX解析 只能查询
由于SAX是基于时间驱动的,所以要有 解析器 和 事件处理器
解析器
- 获得解析器的工厂
- 获取解析器对象
- 解析XML (XML文件地址,事件处理器)
解析器采用SAX方式在解析某个XML文档时,它只要解析到XML文档的一个组成部分,都会去调用事件处理器的一个方法,解析器在调用事件处理器的方法时,会把当前解析到的xml文件内容作为方法的参数传递给事件处理器。
事件处理器由程序员编写,程序员通过事件处理器中方法的参数,就可以很轻松地得到sax解析器解析到的数据,从而可以决定如何对数据进行处理。
事件处理器
- 自己编写类,继承DefaultHandler,重写三个方法
- startDocument()
- startElement() 重写
- characters() 重写
- endElement() 重写
- endDocument()
import javax.xml.parsers.ParserConfigurationException;
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;
/**
* SAX的入门
* @author limaoquan
*
*/
public class JaxpSaxTest {
public static void main(String[] args) {
}
/**
* 获取所有解析的内容
* @throws Exception
* @throws ParserConfigurationException
*/
public static void run1() throws ParserConfigurationException, Exception{
//获取Sax的解析器工厂
SAXParserFactory factory = SAXParserFactory.newInstance();
//获取解析器
SAXParser parser = factory.newSAXParser();
//解析
parser.parse("src/book2.xml", new MyHandler());
}
}
/**
* 获取标签作者的文本内容
* @author limaoquan
*
*/
class MyHandler2 extends DefaultHandler{
private boolean flag = false;
@Override
public void startElement(String uri, String localName, String qName,
Attributes attributes) throws SAXException {
if("作者".equals(qName)){
flag = true;
}
}
@Override
public void characters(char[] ch, int start, int length)
throws SAXException {
String str = new String(ch, start, length);
if(flag){
System.out.println(str);
}
}
@Override
public void endElement(String uri, String localName, String qName)
throws SAXException {
flag = false;
}
}
class MyHandler extends DefaultHandler{
/**
* 只要一解析到开始标签的时候,默认调用该方法
*/
@Override
public void startElement(String uri, String localName, String qName,
Attributes attributes) throws SAXException {
System.out.println("开始标签:"+ qName);
}
/**
* 只要解析到文本内容,默认调用该方法
*/
@Override
public void endElement(String uri, String localName, String qName)
throws SAXException {
System.out.println("结束标签:"+qName);
}
/**
* 解析到结束标签的时候,默认调用该方法
*/
@Override
public void characters(char[] ch, int start, int length)
throws SAXException {
String str = new String(ch, start, length);
System.out.println(str);
}
}
Dom4j
Dom4j是一个简单、灵活的开放源代码的库
使用Dom4j需要下载dom4j相应的jar包
- 查找标签文本
- 创建解析器 new SAXReader()
- 解析xml read()
- 获取根节点 root = getRootElement()
- 获取所有指定标签的集合 root.elements(标签名)
- 返回List集合,可以遍历,或者getIndex() 获取Element对象
- 获取文本内容 getText()
- 添加子节点
- 创建解析器 new SAXReader()
- 解析xml read()
- 获取根节点 root = getRootElement()
- 获取所有指定标签的集合 root.elements(标签名)
- 直接调用addElement()设置子节点
- 使用setTest()设置文本
- 回写xml文件
- 在指定位置添加子节点
- 创建元素标签节点 DocumentHelper.createElement()
- 设置文本 setText()
- 获取所有指定标签的集合 root.elements(标签名), 返回list
- 通过list.add(index, element), 在内存中加入子元素
- 回写xml文件
- 修改节点文本
- 找到指定的节点
- 修改文本内容 setText()
- 删除节点
- 找到要删除的节点
- 通过父节点调用remove()方法删除
/**
* 获取作者的文本内容
* @throws Exception
*/
public static void run1() throws Exception{
//获取解析器对象
SAXReader reader = new SAXReader();
//解析XML,返回Document对象
Document document = reader.read("src/book2.xml");
//获取根节点(书架标签)
Element root = document.getRootElement();
//获取书的节点,获取第二本书
List books = root.elements("书");
Element book2 = books.get(1);
//获取作者的标签
Element author = book2.element("作者");
//获取文本内容
String str = author.getText();
}
/**
* 在第二本书下添加子节点
* @throws Exception
*/
public static void run2() throws Exception{
//获取解析器对象
SAXReader reader = new SAXReader();
//解析XML 反回Document对象
Document document = reader.read("src/book2.xml");
//获取根节点
Element root = document.getRootElement();
//获取第二本书
Element book2 = (Element)root.elements("书").get(1);
// 可以直接在第二本书下添加节点,设置文本内容
book2.addElement("猫").setText("你是猫");
//创建漂亮的格式
OutputFormat format = OutputFormat.createPrettyPrint();
//回写
XMLWriter writer = new XMLWriter(new FileOutputStream("src/book2.xml"),format);
writer.write(document);
writer.close();
}
/**
* 在第二本书的作者标签之前添加团购价的标签
* @throws Exception
*/
public static void run3() throws Exception{
//获取解析器对象
SAXReader reader = new SAXReader();
//解析XML 反回Document对象
Document document = reader.read("src/book2.xml");
//获取根节点
Element root = document.getRootElement();
//获取第二本书
Element book2 = (Element)root.elements("书").get(1);
//获取书下的所有子节点,返回list集合
List list = book2.elements();
//创建元素对象 DocumentHelper类
Element dog = DocumentHelper.createElement("狗");
dog.setText("dagoudagou");
//list.add(index,Element);
list.add(1,dog);
//回写
XMLWriter writer = new XMLWriter(new FileOutputStream("src/book2.xml"));
writer.write(document);
writer.close();
}
/**
* 删除子节点
* 删除第二本书下的锚节点
*/
public static void run4() throws Exception{
//获取解析器对象
SAXReader reader = new SAXReader();
//解析XML 反回Document对象
Document document = reader.read("src/book2.xml");
//获取根节点
Element root = document.getRootElement();
//获取猫
Element book2 = (Element)root.elements("书").get(1);
Element cat = book2.element("猫");
//通过猫的父节点删除猫
book2.remove(cat);
//回写
XMLWriter writer = new XMLWriter(new FileOutputStream("src/book2.xml"));
writer.write(document);
writer.close();
}
Dom4j获得Document对象的三种方式:
读取xml文档
SAXReader reader = new SAXReader();
Document document = reader.read(new File("input.xml"));解析XML形式的文本
String text = "";
Document document = DocumentHelper.parseText(text);主动创建document对象
Document document = DocumentHelper.createDocument();
//创建根节点
Element root = document.addElement("members");
节点对象
获取文档的根节点
Element root = document.getRootElement();取得某个节点的子节点
Element element = node.element("标签名")获取节点的文字
String text = node.getText();设置节点文字
element.setText();取得某个节点下所有名为member的子节点,并遍历
List nodes = rootElm.elements("member");
for(iterator it = nodes.iterator();it.hasNext(); ){
Element elem = (Element)it.next();
//do something ...
}对某节点下的所有子节点进行遍历
for(iterator it = root.elementiterator();it.hasNext(); ){
Element elem = (Element)it.next();
//do something ...
}
在某个节点下添加子节点
Element ageElm = newMemberElm.addElement("age");删除某节点
parentElm.remove(childElm);添加一个CDATA节点
Element contenElm = infoElm.addElement("content");
contentElm.addCDATA(diary.getContent());
节点对象的属性
取得某节点下的某属性
Element root = document.getRootElement();
//属性名name
Attribute attribute = root.attribute("size");取得属性的文字
String text = attribute.getText();删除某属性
Attribute attribute = root.attribute("size");
root.remove(attribute);遍历某节点的所有属性
Element root = document.getRootElement();
for(Iterator it = root.attributeIterator(); it.hasNext();){
Attribute attribute = (Attribute)it.next();
String text = attribute.getText();
System.out.println(text);
}设置某节点的属性和文字
newMemberElm.addAttribute("name","sitinspring");设置属性的文字
attribute.setText("sitinspring");
将文档写入XML文件
文档中全为英文,不设置编码,直接写入
XMLWriter writer = new XMLWriter(new FileWriter("output.xml"));
writer.write(document); //此document为之前建立的Document对象
writer.close();文档中有中文,设置编码格式
OutputFormat format = OutputFormat.createPrettyPrint();
//指定XML编码
format.setEncoding("GBK");
XMLWriter writer = new XMLWriter(new FileWriter("output.xml"),format);
writer.write(document); //此document为之前建立的Document对象
writer.close();
Dom4j在指定位置插入节点
Step:
- 得到插入位置的节点列表(list)
- 调用list.add(index,element), 由index决定element的插入位置
- Element元素可以通过DocumentHelpler对象得到
Element aaa = DocumentHelper.createElement("aaa");
aaa.setText("aaa");
List list = root.element("书").elements();
list.add(1,aaa);
//更新document
字符串与XML的转换
字符串转化为XML
String text = " ";setinsping
Document document = DocumentHelper.parseText(text);将文档或节点的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();
Dom4j对XPATH的支持
导入包 jaxen-1.1-beta-6.jar
只能使用Node中的两个方法:
- selectNodes()
- selectNode()
Xpath的语法
- /AAA/BBB/CCC 获取的CCC的节点
- //BBB 无论层级关系,所有的BBB都找到
- //DDD/BBB 所有DDD下的BBB元素
- /AAA/CCC/* CCC下的所有元素
- /*/*/*/BBB 所有有3个祖元素的BBB元素
- //* 所有元素
- /AAA/BBB[1] AAA下的第一个BBB
- /AAA/BBB[last()] AAA下最后一个BBB
- //@id id属性
- //BBB[@name] 选择有name属性的BBB元素
- //BBB[@*] 选择有任意属性的BBB元素
- //BBB[note(@*)] 选择没有属性的BBB元素