基础
XML解析器有二类,分别是DOM和SAX。
DOM
DOM解析器在解析XML文档时,会把文档中的所有元素,按照其出现的层次关系,解析成一个个Node对象(节点)。
很方便对文档进行遍历 对文档curd也特别方便 xml文档比较大的时候,dom解析占用的内存也会比较大,浪费系统资源。所以dom解析这种方式不适合解析大的xml文档。
SAX
解析文件速度快,占用资源(内存)少。 sax解析只适合读取文档数据,不适合对文档进行增删改。
1 DOM一次性将整个XML文件读到内存,形成一个倒状的树形结构
2 SAX多次将整个XML文件读到内存
SAX采用事件处理的方式解析XML文件,利用 SAX 解析 XML 文档,涉及两个部分:解析器和事件处理器:
解析器可以使用JAXP的API创建,创建出SAX解析器后,就可以指定解析器去解析某个XML文档。
解析器采用SAX方式在解析某个XML文档时,它只要解析到XML文档的一个组成部分,都会去调用事件处理器的一个方法,解析器在调用事件处理器的方法时,会把当前解析到的xml文件内容作为方法的参数传递给事件处理器。
事件处理器由程序员编写,程序员通过事件处理器中方法的参数,就可以很轻松地得到sax解析器解析到的数据,从而可以决定如何对数据进行处理。
3 Document对象代表XML文件在内存中的映像
4)dom4j常用的API如下:
SAXReader saxReader = new SAXReader(); SAXReader是dom4j的核心类
Document document = saxReader.read("*.xml")
Document.getRootElement()
Element.getName()
Element.elements():取得该元素下的所有直接子元素
Element.elementText():从一个元素导航到另一个元素且取出该元素的文本
Element.element("车牌") :从一个元素导航到另一个元素
Element.attributeValue("出产时间"):取得一个元素对应的属性
Element.addElement("单价").setText("40"):添加新元素,同时设置该元素文本的值
OutputFormat format = OutputFormat.createPrettyPrint():使用缩格形式写XML文件
XMLWriter xmlWriter = new XMLWriter(os,format):构造XML写入器
xmlWriter.write(document):将内存中的document对象写入硬盘
firstCarElement.remove(firstCarPriceElement):从直接父元素删除直接子元素
//firstCarPriceElement.getParent().remove(firstCarPriceElement):从直接父元素删除直接子元素
5 基于dom4j的xpath技术
能够在xml文件中,快速定位需要元素,无需从根元素一个一个的导航到需要的子元素
Document.selectNodes():取得所有符合xpath格式的元素
Document.selectSingleNode():取得所有符合xpath格式的元素的第一个元素
Node类型是Element/Text/Attribute/Document/...类型的父接口
6练手
dom4j解析文件
<?xml version="1.0" encoding="UTF-8"?>
<车辆清单>
<汽车>
<车牌 出产时间="2010年">奥迪</车牌>
<产地>北京</产地>
<单价>30</单价>
</汽车>
<汽车>
<车牌 出产时间="2011年">本田</车牌>
<产地>广州</产地>
<单价>60</单价>
</汽车>
</车辆清单>
代码
import java.io.File;
import java.io.FileOutputStream;
import java.io.OutputStream;
import java.util.List;
import org.dom4j.Document;
import org.dom4j.DocumentException;
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;
//使用dom4j操作xml文件的cud
public class Demo2 {
@Test
public void showXml() throws Exception {
// 创建dom4j解析器
SAXReader saxReader = new SAXReader();
// 加载需要解析的xml文件
Document document = saxReader.read(new File("src/cn/feizhou/xml/dom4j/car.xml"));
// 取得根元素
Element rootElement = document.getRootElement();
// 显示根元素的名称
System.out.println(rootElement.getName());
// 取得根元素下的子元素
List<Element> elementList = rootElement.elements();
System.out.println("共有" + elementList.size() + "辆车");
for (Element e : elementList) {
System.out.println("车牌:" + e.elementText("车牌"));
System.out.println("产地:" + e.elementText("产地"));
System.out.println("出产时间:" + e.element("车牌").attributeValue("出产时间"));
System.out.println("------------------------------");
}
}
@Test
/**
* 添加元素
*
* @throws Exception
*/
public void create() throws Exception {
Document document = getDocument();
Element rootElement = document.getRootElement();
// 取得第一辆汽车
Element firstCarElement = (Element) rootElement.elements().get(0);
// 添加新元素"单价",并设置文本为30
firstCarElement.addElement("单价").setText("40");
// 将内存中的xml文件写到硬盘中
write2xml(document, "src/cn/feizhou/xml/dom4j/car.xml");
}
@Test
/**
* 修改元素
*
* @throws Exception
*/
public void update() throws Exception {
Document document = getDocument();
Element rootElement = document.getRootElement();
Element firstCarElement = (Element) rootElement.elements().get(0);
firstCarElement.element("单价").setText("60");
write2xml(document, "src/cn/feizhou/xml/dom4j/car.xml");
}
@Test
/**
* 删除元素
*
* @throws Exception
*/
public void delete() throws Exception {
Document document = getDocument();
Element rootElement = document.getRootElement();
Element firstCarElement = (Element) rootElement.elements().get(0);
Element firstCarPriceElement = firstCarElement.element("单价");
firstCarElement.remove(firstCarPriceElement);
// firstCarPriceElement.getParent().remove(firstCarPriceElement);
write2xml(document, "src/cn/feizhou/xml/dom4j/car.xml");
}
/**
* 字符串转xml
*
* @throws Exception
*/
@Test
public void String2XML() throws Exception {
String text = "<root><res>这是根元素</res></root>";
Document document = DocumentHelper.parseText(text);
write2xml(document, "src/cn/feizhou/xml/dom4j/string2xml.xml");
}
/**
* xml转字符串
*
* @throws Exception
*/
@Test
public void XML2String() throws Exception {
SAXReader saxReader = new SAXReader();
Document document = saxReader.read(new File("src/cn/feizhou/xml/dom4j/car.xml"));
Element rootElement = document.getRootElement();
Element firstCarElement = (Element) rootElement.elements().get(0);
String xml = firstCarElement.asXML();
System.out.println("xml转字符:" + xml);
}
/**
* 指定插入次序,默认插入到最后
*
* @throws Exception
*/
@Test
public void insertElement() throws Exception {
SAXReader saxReader = new SAXReader();
Document document = saxReader.read(new File("src/cn/feizhou/xml/dom4j/car.xml"));
List<Element> elementList = document.getRootElement().elements();
Element newCarElement = DocumentHelper.createElement("汽车");
newCarElement.setText("这是我的汽车");
elementList.add(1, newCarElement);
write2xml(document, "src/cn/feizhou/xml/dom4j/car.xml");
}
/**
* 创建空XML
*
* @throws Exception
*/
@Test
public void createXML() throws Exception {
Document document = DocumentHelper.createDocument();
document.addElement("root").setText("这是根元素");
write2xml(document, "src/cn/feizhou/xml/dom4j/empty.xml");
}
/**
* 将Document写入到xml中
*
* @param document
* @throws Exception
*/
private void write2xml(Document document, String xmlPath) throws Exception {
// 将Document写入到xml中
// 格式:非紧密,内容多行显示,方便阅读
OutputFormat format = OutputFormat.createPrettyPrint();
// 格式:紧密,内容一行显示
// OutputFormat format = OutputFormat.createCompactFormat()
OutputStream os = new FileOutputStream(xmlPath);
XMLWriter xmlWriter = new XMLWriter(os, format);
xmlWriter.write(document);
xmlWriter.close();
}
/**
* 读取xml,并转化为document
*
* @return
* @throws Exception
*/
private Document getDocument() throws Exception {
// 创建dom4j解析器
SAXReader saxReader = new SAXReader();
// 加载需要解析的xml文件
Document document = saxReader.read(new File("src/cn/feizhou/xml/dom4j/car.xml"));
return document;
}
}
xpath读取xml
//使用xpath技术取得xml文件中任意级别下的内容
public class Demo1 {
public static void main(String[] args) throws Exception {
SAXReader reader = new SAXReader();
Document document = reader.read(new File("src/cn/feizhou/xml/xpath/car.xml"));
String xpath = "//单价";
Element element = (Element) document.selectSingleNode(xpath);
System.out.println("第一辆汽车的单价是:" + element.getText());
//List<Element> elementList = document.selectNodes(xpath);
//System.out.println("第二辆汽车的单价是:" + elementList.get(1).getText());
}
}
结果:第一辆汽车的单价是:30
sax解析器解析xml文件
import java.io.File;
import javax.xml.parsers.SAXParser;
import javax.xml.parsers.SAXParserFactory;
import org.xml.sax.Attributes;
import org.xml.sax.helpers.DefaultHandler;
//使用sax解析器解析xml文件
public class Demo1 {
public static void main(String[] args) throws Exception {
//创建SAX解析器工厂
SAXParserFactory factory = SAXParserFactory.newInstance();
//创建SAX解析器
SAXParser saxParser = factory.newSAXParser();
//加载xml文件
saxParser.parse(
new File("src/cn/feizhou/xml/sax/car.xml"),
new MyHandler());
}
}
//自定义SAX处理器
class MyHandler extends DefaultHandler{
private long begin;
public void startDocument(){
System.out.println("解析XML文件开始");
begin = System.currentTimeMillis();
}
public void endDocument() {
System.out.println("解析XML文件结束");
long end = System.currentTimeMillis();
System.out.println("解析XML共用" + (end-begin) + "毫秒");
}
public void startElement(
String uri,
String localName,
String qName,
Attributes attributes){
//元素名称
System.out.println("<"+qName+">");
//属性数量
System.out.println("有"+attributes.getLength()+"个属性");
//属性值
System.out.println(attributes.getValue("出产时间"));
}
public void endElement(
String uri,
String localName,
String qName){
System.out.println("</"+qName+">");
}
public void characters(
char[] ch,
int start,
int length){
//元素值
String content = new String(ch,start,length);
if(content.trim().length()>0){
System.out.println(content);
}
}
}
结果
解析XML文件开始
<车辆清单>
有0个属性
null
<汽车>
有0个属性
null
<车牌>
有1个属性
2011年
奥迪
</车牌>
<产地>
有0个属性
null
北京
</产地>
<单价>
有0个属性
null
30
</单价>
</汽车>
</车辆清单>
解析XML文件结束
解析XML共用2毫秒
上面引用的包
dom4j-1.6.1.jar
jaxen-1.1-beta-6.jar
使用DOM解析器解析XML文件
1 理解dom解析器机制
1)dom解析和dom4j原理一致
2)Node是所有元素的父接口
3)常用的API:
DocumentBuilderFactory factory = DocumentBuilderFactory.newInstance();取得DOM解析器工厂
DocumentBuilder domParser = factory.newDocumentBuilder();取得DOM解析器
domParser.parse(*.xml)加载需要解析的XML文件
Document.getDocumentElement()取得XML文件的根元素/节点
Element.getNodeName():取得根元素
Element.getElementsByTagName("汽车")取得"汽车"元素的集合
NodeList.item(i)取得第N个元素,从0开始
Element.getTextContent():取得元素的文本内容
Element.getAttributes().getNamedItem("出产时间").getTextContent():取得元素中某属性的值
document.createElement("汽车");创建新元素
Element.setTextContent("我的汽车");设置元素的内容
Element.appendChild(newCarElement);在尾部添加元素
Element.insertBefore(newCarElement,
rootElement.getElementsByTagName("汽车").item(1));在指定的元素前添加元素
TransformerFactory tf = TransformerFactory.newInstance();创建输出工厂
Transformer transformer = tf.newTransformer();创建输出对象
Source source = new DOMSource(document);创建内存的document对象
Result result = new StreamResult(new File("XXX/car.xml"));指定输出的目标地点
transformer.transform(source,result);将document对象输出到xml文件中
Element.setTextContent("深圳");更新元素的内容
Element.removeChild(secondCarElement);在父元素基础上删除直接子元素
4)dom解析器会将空白字符当作有效元素对待
5)要让dom解析器将空白字符忽略,必须满足二条件
a)对XML文件必须写一个DTD约束
b)factory.setIgnoringElementContentWhitespace(true);
6)dom类解析器和sax类解析器
a)dom是一次性加载到内容,形成document对象,人工导航,适合curd
b)sax是分次性加载到内容,sax解析器导航,但程序员需要编写sax处理器,必须扩展DefaultHandler类
import java.io.File;
import java.io.IOException;
import javax.xml.parsers.DocumentBuilder;
import javax.xml.parsers.DocumentBuilderFactory;
import javax.xml.transform.Result;
import javax.xml.transform.Source;
import javax.xml.transform.Transformer;
import javax.xml.transform.TransformerFactory;
import javax.xml.transform.dom.DOMSource;
import javax.xml.transform.stream.StreamResult;
import org.junit.Test;
import org.w3c.dom.Document;
import org.w3c.dom.Element;
import org.w3c.dom.NodeList;
import org.xml.sax.SAXException;
public class Demo2 {
@Test
/**
* 显示
* @return
*/
public void showElements() throws Exception{
Document document = getDocument();
Element rootElement = document.getDocumentElement();
//根元素
System.out.println("根元素为:"+rootElement.getNodeName());
//获取标签名为汽车的所有元素
NodeList nodeList = rootElement.getElementsByTagName("汽车");
System.out.println("共有:" + nodeList.getLength()+"辆汽车");
System.out.println("+++++++第一辆汽车的信息+++++++++");
for(int i=0;i<nodeList.getLength();i++){
Element element = (Element) nodeList.item(i);
String band = element.getElementsByTagName("车牌").item(0).getTextContent();
String place = element.getElementsByTagName("产地").item(0).getTextContent();
String price = element.getElementsByTagName("单价").item(0).getTextContent();
String time = element.getElementsByTagName("车牌").item(0).getAttributes().getNamedItem("出产时间").getTextContent();
System.out.println("车牌:" + band);
System.out.println("产地:" + place);
System.out.println("单价:" + price);
System.out.println("出产时间:" + time);
}
}
@Test
/**
* 创建元素并插入元素
* @throws Exception
*/
public void createAndInsert() throws Exception{
Document document = getDocument();
// 创建元素
Element newCarElement = document.createElement("汽车");
newCarElement.setTextContent("我的汽车");
Element rootElement = document.getDocumentElement();
//rootElement.appendChild(newCarElement);
// 插入元素
rootElement.insertBefore(
newCarElement,
rootElement.getElementsByTagName("汽车").item(1));
write2xml(document);
}
@Test
/**
* 修改元素
* @throws Exception
*/
public void update() throws Exception{
Document document = getDocument();
//获取元素
Element secondCarElement = (Element) document.getElementsByTagName("汽车").item(1);
//修改元素
secondCarElement.getElementsByTagName("产地").item(0).setTextContent("深圳");
secondCarElement.getElementsByTagName("车牌").item(0).getAttributes().getNamedItem("出产时间").setTextContent("2012年");
write2xml(document);
}
@Test
/**
* 删除元素
* @throws Exception
*/
public void delete() throws Exception{
Document document = getDocument();
// 获取元素
Element rootElement = document.getDocumentElement();
Element secondCarElement = (Element) rootElement.getElementsByTagName("汽车").item(1);
//删除元素
rootElement.removeChild(secondCarElement);
write2xml(document);
}
/**
*将Document写入xml
* @param document
* @throws Exception
*/
private void write2xml(Document document)throws Exception {
//将内存中的document对象写到外存的xml文件
TransformerFactory tf = TransformerFactory.newInstance();
Transformer transformer = tf.newTransformer();
//源
Source source = new DOMSource(document);
//目
Result result = new StreamResult(new File("src/cn/feihzou/xml/dom/car.xml"));
transformer.transform(source,result);
}
/**
* 获取Document对象
* @return
* @throws Exception
*/
private static Document getDocument() throws Exception {
// 得到创建 DOM 解析器的工厂。
DocumentBuilderFactory factory = DocumentBuilderFactory.newInstance();
//设置dom解析器将空白字符过滤
factory.setIgnoringElementContentWhitespace(true);
//DOM 解析器对象
DocumentBuilder domParser = factory.newDocumentBuilder();
Document document = domParser.parse(new File("src/cn/feihzou/xml/dom/car.xml"));
return document;
}
}