一、XML解析技术概述
1.1、xml解析方式
XML解析方式分为两种:DOM方式和SAX方式 DOM:Document Object Model,文档对象模型。这种方式是W3C推荐的处理XML的一种方式。 SAX:Simple API for XML。这种方式不是官方标准,属于开源社区XML-DEV,几乎所有的XML解析器都支持它。
1.2、XML解析开发技术包
JAXP:是SUN公司推出的解析标准实现。 Dom4J:是开源组织推出的解析开发包。(牛,大家都在用,包括SUN公司的一些技术的实现都在用) JDom:是开源组织推出的解析开发包。
二、JAXP解析开发包简介
JAXP:(Java API for XML Processing)开发包是JavaSE的一部分,它由以下几个包及其子包组成: org.w3c.dom:提供DOM方式解析XML的标准接口 org.xml.sax:提供SAX方式解析XML的标准接口 javax.xml:提供了解析XML文档的类
javax.xml.parsers包中,定义了几个工厂类。我们可以通过调用这些工厂类,得到对XML文档进行解析的DOM和SAX解析器对象。 DocumentBuilderFactory SAXParserFactory
使用JAXP进行DOM解析
javax.xml.parsers 包中的DocumentBuilderFactory用于创建DOM模式的解析器对象 , DocumentBuilderFactory是一个抽象工厂类,它不能直接实例化,但该类提供了一个newInstance方法 ,这个方法会根据本地平台默认安装的解析器,自动创建一个工厂的对象并返回。
获得JAXP中的DOM解析器
- 调用 DocumentBuilderFactory.newInstance() 方法得到创建 DOM 解析器的工厂。
- 调用工厂对象的 newDocumentBuilder方法得到 DOM 解析器对象。
- 调用 DOM 解析器对象的 parse() 方法解析 XML 文档,得到代表整个文档的 Document 对象,进行可以利用DOM特性对整个XML文档进行操作了。
常用方法:
- getElementsByTagName(String tagname) :根据标签名称得到标签,返回NodeList
- createElement(String tagName) :创建标签
- createTextNode(String data) :创建文本
- appendChild(Node newChild) : 把文本添加到标签下面
Document是一个接口,父接口是Node
三、DOM编程
DOM方式解析XML文件
DOM解析编程
代码示例
person1.xml
代码语言:javascript复制<?xml version="1.0" encoding="UTF-8" standalone="no"?>
<person>
<p1>
<name>zhangsan</name>
<age>20</age>
</p1>
<p1>
<name>lisi</name>
<age>30</age>
</p1>
</person>
3.1、实现查找所有name元素的内容
代码语言:javascript复制 public static void getNameText() throws Exception {
/*
* 1、创建一个解析器工厂
* 2、根据这个解析器工厂来创建解析器
* 3、解析xml
*
* 4、获取到name元素 getElementsByTagName(String tagname)
* 5、获取元素具体的文本内容 getTextContent()
* */
//创建解析器工厂
DocumentBuilderFactory builderFactory = DocumentBuilderFactory.newInstance();
//创建解析器
DocumentBuilder documentBuilder = builderFactory.newDocumentBuilder();
//解析xml
Document document = documentBuilder.parse("src/person1.xml");
//获取name标签
NodeList list = document.getElementsByTagName("name");
//遍历nodelist
for(int i=0;i<list.getLength();i ) {
Node node = list.item(i);
String s = node.getTextContent();
System.out.println("content: " s);
}
}
3.2、查询第一个name元素里面的值
代码语言:javascript复制 public static void getFirstName() throws Exception {
/*
* 1、创建解析器工厂
* 2、创建解析器
* 3、解析xml 通过parse
*
* 4、获取所有的name元素
* 5、直接获取第一个元素
* */
//创建解析器工厂
DocumentBuilderFactory documentBuilderFactory = DocumentBuilderFactory.newInstance();
//创建解析器
DocumentBuilder documentBuilder = documentBuilderFactory.newDocumentBuilder();
//解析xml
Document document = documentBuilder.parse("src/person1.xml");
//直接获取到第一个name元素
Node node1 = document.getElementsByTagName("name").item(1);
//获取name元素里面的值
String s = node1.getTextContent();
System.out.println("first name: " s);
}
3.3、实现在第一个p1下面添加 nv
代码语言:javascript复制 public static void addSex() throws Exception {
/*
* 1、创建解析器工厂
* 2、根据解析器工厂,创建解析器
* 3、使用parse方法解析xml
*
* 4、获取到第一个p1元素
* 5、创建sex元素 使用createElement方法创建元素
* 6、创建文本 nv 使用createTextNode方法创建文本
* 7、把文本添加到sex元素下面 使用appendChild添加
*
* 8、把sex元素添加到第一个p1下面 使用appendChild添加
*
* 9、回写xml
*
* */
DocumentBuilderFactory documentBuilderFactory = DocumentBuilderFactory.newInstance();
DocumentBuilder documentBuilder = documentBuilderFactory.newDocumentBuilder();
Document document = documentBuilder.parse("src/person1.xml");
//获取到第一个p1元素
Node p1 = document.getElementsByTagName("p1").item(0);
//创建sex元素
Element sex1 = document.createElement("sex");
//创建文本
Text nv = document.createTextNode("nv");
//添加
sex1.appendChild(nv);
//在p1下面添加sex
p1.appendChild(sex1);
//实现回写xml
TransformerFactory transformerFactory = TransformerFactory.newInstance();
Transformer transformer = transformerFactory.newTransformer();
transformer.transform(new DOMSource(document), new StreamResult("src/person1.xml"));
}
更新XML文档(Transformer)
javax.xml.transform包中的Transformer类用于把代表XML文件的Document对象转换为某种格式后进行输出,例如把xml文件应用样式表后转成一个html文档。利用这个对象,当然也可以把Document对象又重新写入到一个XML文件中。
Transformer类通过transform方法完成转换操作,该方法接收一个源和一个目的地。我们可以通过: javax.xml.transform.dom.DOMSource类来关联要转换的document对象, 用javax.xml.transform.stream.StreamResult 对象来表示数据的目的地。
Transformer对象通过TransformerFactory获得。
3.4、实现修改sex值成nan
代码语言:javascript复制 public static void modifySex() throws Exception {
/*
* 1、创建解析器工厂
* 2、根据解析器工厂,创建解析器
* 3、使用parse方法解析xml
*
* 4、获取到sex元素
* 5、实现修改
* 6、回写xml
* */
DocumentBuilderFactory documentBuilderFactory = DocumentBuilderFactory.newInstance();
DocumentBuilder documentBuilder = documentBuilderFactory.newDocumentBuilder();
Document document = documentBuilder.parse("src/person1.xml");
//获取到sex元素
Node sex = document.getElementsByTagName("sex").item(0);
//实现修改
sex.setTextContent("nan");
//回写xml
TransformerFactory transformerFactory = TransformerFactory.newInstance();
Transformer transformer = transformerFactory.newTransformer();
transformer.transform(new DOMSource(document), new StreamResult("src/person1.xml"));
}
3.5、实现删除第二个p1元素下面的age元素
代码语言:javascript复制 public static void delAge() throws Exception {
/*
* 1、创建解析器工厂
* 2、根据解析器工厂,创建解析器
* 3、使用parse方法解析xml
*
* 4、获取到第二个p1元素下面的age item(1)
* 5、获取p1元素
* 6、执行删除操作
* 7、回写xml
*
* */
DocumentBuilderFactory documentBuilderFactory = DocumentBuilderFactory.newInstance();
DocumentBuilder documentBuilder = documentBuilderFactory.newDocumentBuilder();
Document document = documentBuilder.parse("src/person1.xml");
//获取要删除的age
Node age2 = document.getElementsByTagName("age").item(1);
//获取p1
//第一种方式
Node p1 = document.getElementsByTagName("p1").item(1);
//第二种方式
// age2.getParentNode();
//执行删除操作
p1.removeChild(age2);
//回写xml
TransformerFactory transformerFactory = TransformerFactory.newInstance();
Transformer transformer = transformerFactory.newTransformer();
transformer.transform(new DOMSource(document), new StreamResult("src/person1.xml"));
}
3.6、实现把xml中所有的标签名称显示出来
代码语言:javascript复制 public static void listXml() throws Exception {
/*
* 1、创建解析器工厂
* 2、根据解析器工厂,创建解析器
* 3、使用parse方法解析xml
*
* 4、使用getChildNodes()获取元素下面的子元素
* 5、使用递归操作
*
* */
DocumentBuilderFactory documentBuilderFactory = DocumentBuilderFactory.newInstance();
DocumentBuilder documentBuilder = documentBuilderFactory.newDocumentBuilder();
Document document = documentBuilder.parse("src/person1.xml");
//写一个方法实现查找所有的标签
list1(document);
}
//实现递归查找元素名称
private static void list1(Node node) {
//使用node.getNodeType()判断类型是元素类型,输出
//使用Node里面的ELEMENT_NODE 判断是否是元素节点类型
if(node.getNodeType() == Node.ELEMENT_NODE) {
System.out.println("元素名称:" node.getNodeName());
}
//查找子节点
NodeList list = node.getChildNodes();
//遍历list
for(int i=0;i<list.getLength();i ) {
Node n1 = list.item(i);
//使用递归
list1(n1);
}
}
四、SAX解析
概述
在使用 DOM 解析 XML 文档时,需要读取整个 XML 文档,在内存中构架代表整个 DOM 树的Doucment对象,从而再对XML文档进行操作。此种情况下,如果 XML 文档特别大,就会消耗计算机的大量内存,并且容易导致内存溢出。
SAX解析允许在读取文档的时候,即对文档进行处理,而不必等到整个文档装载完才会文档进行操作。
SAX的事件处理方式解析XML文件
SAX采用事件处理的方式解析XML文件,利用 SAX 解析 XML 文档,涉及两个部分:解析器和事件处理器:
解析器可以使用JAXP的API创建,创建出SAX解析器后,就可以指定解析器去解析某个XML文档。
解析器采用SAX方式在解析某个XML文档时,它只要解析到XML文档的一个组成部分,都会去调用事件处理器的一个方法,解析器在调用事件处理器的方法时,会把当前解析到的xml文件内容作为方法的参数传递给事件处理器。
事件处理器由程序员编写,程序员通过事件处理器中方法的参数,就可以很轻松地得到sax解析器解析到的数据,从而可以决定如何对数据进行处理。
4.1、SAX解析原理
- SAX 是事件驱动的 XML 处理方法
- 它是基于事件驱动的
- startElement() 回调在每次 SAX 解析器遇到元素的起始标记时被调用
- characters() 回调为字符数据所调用
- endElement() 为元素的结束标记所调用
- DefaultHandler类(在 org.xml.sax.helpers 软件包中)来实现所有这些回调,并提供所有回调方法默认的空实现
4.2、SAX的事件驱动模型
4.3、SAX DocumentHandler示例
SAX 解析器采用了基于事件的模型,它在解析XML文档的时候可以触发一系列的事件
发生相应事件时,将调用一个回调方法
4.4、使用SAX方式解析XML
使用SAXParserFactory创建SAX解析工厂
SAXParserFactory spf = SAXParserFactory.newInstance();
通过SAX解析工厂得到解析器对象
SAXParser sp = spf.newSAXParser();
通过解析器对象解析xml文件
sp .parse("book.xml“,new XMLContentHandler());
这里的XMLContentHandler 继承 DefaultHandler
4.5、SAX代码例子
打印整个xml文档的内容
代码语言:javascript复制public class TestSax {
public static void main(String[] args) throws Exception {
//创建解析器工厂
SAXParserFactory saxParserFactory = SAXParserFactory.newInstance();
//创建解析器
SAXParser saxParser = saxParserFactory.newSAXParser();
//执行parse方法
saxParser.parse("person.xml", new MyDefaultHandler());
}
}
class MyDefaultHandler extends DefaultHandler {
@Override
public void startElement(String uri, String localName, String qName,Attributes attributes) throws SAXException {
System.out.print("<" qName ">");
}
@Override
public void characters(char[] ch, int start, int length)
throws SAXException {
System.out.print(new String(ch,start,length));
}
@Override
public void endElement(String uri, String localName, String qName)
throws SAXException {
System.out.print("</ " qName ">");
}
}
获取所有的name的值
代码语言:javascript复制public class TestSax {
public static void main(String[] args) throws Exception {
//创建解析器工厂
SAXParserFactory saxParserFactory = SAXParserFactory.newInstance();
//创建解析器
SAXParser saxParser = saxParserFactory.newSAXParser();
//执行parse方法
saxParser.parse("person.xml", new MyDefaultHandler1());
}
}
class MyDefaultHandler1 extends DefaultHandler {
boolean flag = false;
@Override
public void startElement(String uri, String localName, String qName,Attributes attributes) throws SAXException {
if("name".equals(qName)) {
flag = true;
}
}
@Override
public void characters(char[] ch, int start, int length)
throws SAXException {
if(flag == true) {
System.out.println(new String(ch,start,length));
}
}
@Override
public void endElement(String uri, String localName, String qName)
throws SAXException {
if("name".equals(qName)) {
flag = false;
}
}
}
五、DOM4J解析XML文档
5.1、概述
- Dom4j是一个简单、灵活的开放源代码的库。Dom4j是由早期开发JDOM的人分离出来而后独立开发的。与JDOM不同的是,dom4j使用接口和抽象基类,虽然Dom4j的API相对要复杂一些,但它提供了比JDOM更好的灵活性。
- Dom4j是一个非常优秀的Java XML API,具有性能优异、功能强大和极易使用的特点。现在很多软件采用的Dom4j,例如Hibernate,包括sun公司自己的JAXM也用了Dom4j。
- 使用Dom4j开发,需下载dom4j相应的jar文件。
- JAXM(Java API for XML Messaging简称JAXM)是为Java平台上的应用程序定义的API,用以通过XML(以及SOAP)发送和接收消息,支持同步消息和异步消息。
5.2、Document对象
DOM4j中,获得Document对象的方式有三种:
1.读取XML文件,获得document对象 SAXReader reader = new SAXReader(); Document document = reader.read(new File(“input.xml”));
2.解析XML形式的文本,得到document对象 String text = “”; Document document = DocumentHelper.parseText(text);
3.主动创建document对象. Document document = DocumentHelper.createDocument(); //创建根节点 Element root = document.addElement(“members”);
5.3、节点对象(获取节点)
1.获取文档的根节点. Element root =document.getRootElement(); 2.取得某个节点的子节点. List list = root.elements(“a”); Element book2 = (Element)list.get(1);
Element element=node.element(“书名");
3.取得节点的文字 String text=node.getText();
5.4、节点对象(添加节点)
在age节点下添加age节点 Element age = a2.addElement(“age”); 设置文本内容 age.setText(“400”); 将文档写入XML文件 XMLWriter writer = new XMLWriter(new FileOutputStream(“src/4.xml”) writer.write(document); writer.close();
5.5、节点对象(在特定位置添加节点)
使用DocumentHelper //获取a下面节点 List list = book.elements(); //创建文本和cc标签 Element cc = DocumentHelper.createElement(“cc”); cc.setText(“测试”); //在特定位置添加:第一个参数表示元素位置,第二个参数表示添加的元素在第一个参数表示元素之前 list.add(1, cc);
5.6、节点对象(修改、删除节点)
//获取a节点 Element a2 = (Element)root.elements(“a”).get(1); //获取第二个a下的name Element name2 = a2.element(“name”); //修改name值 name2.setText(“东方不败”); //删除节点 age2.getParent().remove(age2);
5.7、节点对象属性
获取属性值 Element a1 = (Element)root.elements(“a”).get(0);
String aa = a1.attributeValue(“aa”);
设置某节点的属性和文字. newMemberElm.addAttribute(“name”, “sitinspring”);
设置属性的文字 Attribute attribute=root.attribute(“name”); attribute.setText(“sitinspring”);
5.8、将文档写入XML文件
1.文档中全为英文,不设置编码,直接写入的形式
XMLWriter xmlWriter = new XMLWriter(new FileOutputStream(“src/persons.xml”));
writer.write(document);
writer.close();
2.文档中含有中文,设置编码格式写入的形式;设置回写xml格式化方式
//设置格式化方式
OutputFormat format = OutputFormat.createPrettyPrint(); // 指定XML编码
format.setEncoding(“utf-8");
XMLWriter writer = new XMLWriter(newFileWriter(“output.xml”),format); writer.write(document); writer.close();
5.9、案例
使用前一定要导包
使用dom4j查询name元素里面的内容
代码语言:javascript复制public static void selectNode1() throws Exception {
/*
* 1、获取dom4j的解析器
* 2、执行read方法,返回document
* 3、获取到name
* * 获取到根节点 getRootElement
* * 获取到第一个p1元素
* - element(QName qName) :获取某一个元素(第一个)
* - elements(QName qName) :获取所有元素 name
* - elements() :获取p1下面的所有元素
* 4、获取name里面的内容
* getText();
* */
//获取dom4j的解析器
SAXReader saxReader = new SAXReader();
//获取document
Document document = saxReader.read("src/person.xml");
//获取到根节点
Element root = document.getRootElement();
//获取第一个p1
Element p1 = root.element("p1");
//获取p1下面的元素
// Element name = p1.element("name");
//获取name里面的内容
// String s = name.getText();
// System.out.println(s);
//<name>东方不败</name>
// <age>30</age>
List<Element> list = p1.elements();
for (Element e1 : list) {
String s = e1.getText();
System.out.println(s);
}
}
获取xml中所有name值
代码语言:javascript复制 public static void getNames() throws Exception {
/*
* 1、获取dom4j的解析器
* 2、执行read方法,返回document
* 3、获取根节点
*
* 4、获取所有的p1
* 5、循环p1的list
* 6、获取name内容
* */
SAXReader saxReader = new SAXReader();
Document document = saxReader.read("src/person.xml");
Element root = document.getRootElement();
//获取所有p1
List<Element> list = root.elements("p1");
//循环p1的list
for (Element p1 : list) {
//每次得到的p1,获取p1下面的name
Element name1 = p1.element("name");
String s = name1.getText();
System.out.println("name: " s);
}
}
在第一个p1下面添加女
代码语言:javascript复制 public static void addSex() throws Exception {
/*
* 1、获取dom4j的解析器
* 2、执行read方法,返回document
* 3、获取根节点
*
* 4、获取到第一个p1
* 5、在第一个p1下面添加 直接使用addElement添加sex
* 6、向sex里面添加内容 setText("女");
*
* 7、回写xml
*
* */
SAXReader saxReader = new SAXReader();
Document document = saxReader.read("src/person.xml");
Element root = document.getRootElement();
//获取到第一个p1
Element p1 = root.element("p1");
//向p1下面添加sex元素
Element sex = p1.addElement("sex");
//向sex里面添加内容
sex.setText("女");
//回写操作
//格式化操作
//方式一
XMLWriter xmlWriter = new XMLWriter(new FileOutputStream("person1.xml"));
xmlWriter.write(document);
//方式二
OutputFormat format = OutputFormat.createPrettyPrint();
XMLWriter xmlWriter = new XMLWriter(new FileOutputStream("person1.xml"), format);
xmlWriter.write(document);
//关闭
xmlWriter.close();
}
在女之前添加 100
代码语言:javascript复制 public static void addId() throws Exception {
/*
* 1、获取dom4j的解析器
* 2、执行read方法,返回document
* 3、获取根节点
*
* 4、获取到第一个p1
* 5、执行添加操作
* * 得到要添加的位置
* * 创建要添加的元素
* * 在p1下面执行elements方法得到p1下面的所有元素 list
* * add(int index, E element)
* 6、回写xml
*
* */
SAXReader saxReader = new SAXReader();
Document document = saxReader.read("src/person.xml");
Element root = document.getRootElement();
//获取第一个p1
Element p1 = root.element("p1");
//获取p1下面的所有元素
List<Element> list = p1.elements();
//创建id元素
Element id1 = DocumentHelper.createElement("id");
id1.setText("100");
//在特定位置添加
list.add(3, id1);
//回写xml
OutputFormat format = OutputFormat.createPrettyPrint();
// OutputFormat format = OutputFormat.createCompactFormat();
// format.setEncoding("utf-8");
XMLWriter xmlWriter = new XMLWriter(new FileOutputStream("src/person.xml"), format);
xmlWriter.write(document);
xmlWriter.close();
}
**把女 修改男 **
代码语言:javascript复制public static void modifySex() throws Exception {
/*
* 1、获取dom4j的解析器
* 2、执行read方法,返回document
* 3、获取根节点
*
* 4、获取p1
* 5、获取p1下面的sex
* 6、完成修改操作
* 7、回写xml
* */
SAXReader saxReader = new SAXReader();
Document document = saxReader.read("person1.xml");
//获取根节点
Element root = document.getRootElement();
//获取第一个p1
Element p1 = root.element("p1");
//获取p1下面的sex
Element sex = p1.element("sex");
//修改内容
sex.setText("男");
//回写xml
OutputFormat format = OutputFormat.createPrettyPrint();
XMLWriter xmlWriter = new XMLWriter(new FileOutputStream("src/person.xml"), format);
xmlWriter.write(document);
xmlWriter.close();
}
**删除第一个p1下面的100 **
代码语言:javascript复制 public static void delId() throws Exception {
/*
* 1、获取dom4j的解析器
* 2、执行read方法,返回document
* 3、获取根节点
*
* 4、获取到第一个p1
* 5、获取p1下面的id
*
* 6、执行删除操作 通过父节点删除
* 7、回写xml
* */
SAXReader saxReader = new SAXReader();
Document document = saxReader.read("person1.xml");
//获取根节点
Element root = document.getRootElement();
//获取第一个p1
Element p1 = root.element("p1");
//获取p1下面的id
Element id1 = p1.element("id");
//先获取id元素的父元素
//另外一个获取父元素的方式
Element p_id = id1.getParent();
//执行删除操作
p_id.remove(id1);
//回写xml
OutputFormat format = OutputFormat.createPrettyPrint();
XMLWriter xmlWriter = new XMLWriter(new FileOutputStream("src/person1.xml"),format);
xmlWriter.write(document);
xmlWriter.close();
}
获取p1上面的id属性值
代码语言:javascript复制 public static void getValues() throws Exception {
/*
* 1、获取dom4j的解析器
* 2、执行read方法,返回document
* 3、获取根节点
*
* 4、获取到p1 element方法
* 5、获取p1上面的属性值 attributeValue("属性名称")
*
* */
SAXReader saxReader = new SAXReader();
Document document = saxReader.read("person.xml");
//获取根节点
Element root = document.getRootElement();
//获取p1
Element p1 = root.element("p1");
//获取p1上面的属性
String s = p1.attributeValue("id");
System.out.println(s);
}
六、Dom4J配合XPath使用
XPath概述
XPath即为XML路径语言(XML Path Language),它是一种用来确定XML文档中某部分位置的语言。XPath基于XML的树状结构,提供在数据结构树中找寻节点的能力。起初 XPath 的提出的初衷是将其作为一个通用的、介于XPointer与XSL间的语法模型。但是 XPath 很快的被开发者采用来当作小型查询语言。
DOM4J对XPath的支持
在DOM4J中,Node接口中的三个方法最为常用:
List selectNodes(String xpathExpression):在当前节点中查找满足XPath表达式的所有子节点;
Node selectSingleNode(String xpathExpression):在当前节点中查找满足XPath表达式的第一个子节点;
String valueOf(String xpathExpression):在当前节点中查找满足XPath表达式的第一个子节点的文本内容;
案例
注意:使用前要导包
获取xml中所有name元素的内容
代码语言:javascript复制 public static void getNames() throws Exception {
/*
* 1、获取解析器
* 2、执行read方法,返回document
*
* 3、使用xpath获取name元素 返回list结合
* 4、遍历list
* 5、根据每次遍历出来的name元素,获取name的值
* */
//获取解析器
SAXReader saxReader = new SAXReader();
//返回document
Document document = saxReader.read("src/person.xml");
//获取name元素 使用xpath : //name
List<Node> list = document.selectNodes("//name");
//遍历
for (Node node : list) {
//获取值
String s = node.getText();
System.out.println("name: " s);
}
}
获取第一个p1下面的name的内容
代码语言:javascript复制 public static void getFirstName() throws Exception {
/*
* 1、获取解析器
* 2、执行read方法,返回document
*
* 3、使用xpath获取第一个p1下面的name元素 //p1[@id]/name
* 4、得到的name元素,获取内容
*
* */
//获取解析器
SAXReader saxReader = new SAXReader();
//返回document
Document document = saxReader.read("src/person.xml");
//使用xpath 获取第一个p1下面的name元素
Node name1 = document.selectSingleNode("//p1[@id]/name");
//获取name元素的值
String s = name1.getText();
System.out.println("name1: " s);
}