XML(Extensible Markup Language),扩展性标识语言。文件的后缀名为.xml。
XML的作用是传输和存储数据:
- 可作为一种简单的数据库,存储并检索数据;
- 传输约定格式的文件;
- 可作为软件的配置文件。
一、XML入门
声明语法
<?xml version="1.0" encoding="utf-8" standalone="no"?>
<person id="1001" year="2015">
<!-- xml的注释 -->
<nam>张三</nam>
<age>20</age>
</person>
属性:
version xml的版本,1.0(使用)、1.1
encoding xml编码,gbk、utf-8、iso8859-1(不包含中文)
standalone 是否需要依赖其他文件,yes/no
注意标签要区分大小写
标签上可以有属性(多个),但是属性名不可相同
需要显示“<”或者“>”时,需要进行转义: <使用 < >使用 > &使用& ...等等
如果不想转义,可以把内容放入CDATA区,会把特殊字符当作文本内容展示:
<![CDATA[ 内容 ]]>
例如:<![CDATA[ <b>if(a<b && b<c && d>f) {}</b> ]]>
PI指令(可在xml中设置样式,仅对英文标签有效)
语法:
<?xml-stylesheet type=”text/css” href=”css的路径”?>
例子:
<?xml version="1.0" encoding="utf-8"?>
<?xml-stylesheet type="text/css" href="1.css"?>
<person>
<name>张三</name>
<age>20</age>
</person>
1.css文件定义:
name { background-color:red; }
age { background-color:orange;}
约束的技术:
dtd的约束和schema的约束
二、文档类型定义(DTD)
快速了解
文件后缀: .dtd
步骤:
- 看xml中有多少个元素, 有几个元素,在dtd文件中写几个
- 判断元素是简单元素还是复杂元素。
- 复杂元素:有子元素的元素: < !ELEMENT 元素名称(子元素)>
- 简单元素:没有子元素: <! ELEMENT 元素名称 (#PCDATA)>
- 需要在xml文件中引入dtd文件
- < !DOCTYPE 根元素名称 SYSTEM "dtd文件的路径">
例子:
<!ELEMENT person (name,age)>
<!ELEMENT name (#PCDATA)>
<!ELEMENT age (#PCDATA)>
<?xml version="1.0" encoding="utf-8"?>
<!DOCTYPE person SYSTEM "person.dtd">
<person>
<name>张三</name>
<age>20</age>
<a></a> <!--这里就会报错-->
</person>
引入方式
1、 引入外部的 dtd 文件
< !DOCTYPE 根元素名称 SYSTEM "dtd文件的路径">
2、 使用内部的 dtd 文件
< !DOCTYPE 根元素名称 [
<!ELEMENT person (name,age)>
<!ELEMENT name (#PCDATA)
<!ELEMENT age (#PCDATA)>
]>
3、 使用外部的dtd文件(网络上的dtd文件)
<!DOCTYPE 根元素 PUBLIC "DTD名称" "DTD文档的URL" >
后面学到框架 struts2 使用配置文件使用:
< !DOCTYPE struts PUBLIC "Apache softwate Foundateion//DTD Struts Configuration 2.0// EN" "http://struts.apache.orp/dtds/struts-2.0.dtd">
定义元素
语法:
<!ELEMENT 元素名 约束>
1、简单元素(没有子元素的元素)
<! ELEMENT nane (#PCDATA)>
(#PCDATA):约束name是字符串类型,注意必须有括号,如“<name>张三</name>”
EMPTY:元素必须为空没有内容,如“<sex></sex>”
ANY:任意,可为空也可以不为空
2、复杂元素
<!ELEMENT 元素名称 (子元素1,子元素2,子元素3,子元素4)>
规则:
(1)子元素只能出现一次
(2)子元素出现多次怎么办:
+ 表示一次或者多次
? 表示零次或者一次
* 表示零次或者多次(任意次数)
(3)子元素直接使用逗号进行隔开,逗号隔开的顺序表示子元素出现的顺序
(4)子元素直接使用|隔开,表示元素只能出现其中的任意一个(类似枚举)
定义属性
语法:
< !ATTLIST 元素名称
属性名称 属性类型 属性约束
属性名称 属性类型 属性约束
...>
属性类型:
CDATA:表示属性的取值为普通文本字符串。例如:
ID1 CDATA #REQUIRED
ENUMERATED:表示枚举,表示方式为:(aa|bb|cc)
ID2 (red|green|blue) #REQUIRED
ID:表示属性取值不能重复,只能由字母、下划线开始,不能出现空白字符
ID3 ID #REQUIRED
属性约束说明:
#REQUIRED:表示该属性必须出现
ID1 CDATA #REQUIRED
#IMPLIED:表示该属性可有可无
ID1 CDATA #IMPLIED
#FIXED:表示属性的取值是一个固定值,语法格式:#FIXED "固定值"
ID1 CDATA #FIXED "ABC"
直接值:表示属性的取值为该默认值,写的话就按写的值设置
ID1 CDATA "2022"
定义实体
语法:
<!ENTITY 实体名称 "实体的值">
注意:定义实体需要写在内部 dta 里面,如果写在外部的 dtd 里面,有某些浏览器下,内容得不到
例子:
DTD中定义实体:
<!ENTITY copyright "版权归百度所有">
XML中使用实体:
©right; (注意有分号)
案例分析
<?xml version="1.0" encoding="utf-8"?>
<!DOCTYPE TVSCHEDULE [
<!ELEMENT TVSCHEDULE (CHANNEL+)>
<!ELEMENT CHANNEL (BANNER,DAY+)>
<!ELEMENT BANNER (#PCDATA)>
<!ELEMENT DAY (DATE,(HOLIDAY|PROGRAMSLOT+)+)>
<!ELEMENT HOLIDAY (#PCDATA)>
<!ELEMENT DATE (#PCDATA)>
<!ELEMENT PROGRAMSLOT (TIME,TITLE,DESCRIPTION?)>
<!ELEMENT TIME (#PCDATA)>
<!ELEMENT TITLE (#PCDATA)>
<!ELEMENT DESCRIPTION (#PCDATA)>
<!ATTLIST TVSCHEDULE NAME CDATA #REQUIRED>
<!ATTLIST CHANNEL CHAN CDATA #REQUIRED>
<!ATTLIST PROGRAMSLOT VTR CDATA #IMPLIED>
<!ATTLIST TITLE RATING CDATA #IMPLIED>
<!ATTLIST TITLE LANGUAGE CDATA #IMPLIED>
]>
<TVSCHEDULE NAME="CCTV1">
<CHANNEL CHAN="cc0001">
<BANNER>这里是banner</BANNER>
<DAY>
<DATE>2022-01-01</DATE>
<HOLIDAY>这里是假期1</HOLIDAY>
</DAY>
<DAY>
<DATE>2022-01-02</DATE>
<PROGRAMSLOT VTR="ss001">
<TIME>1998</TIME>
<TITLE LANGUAGE="chinese">test title 111</TITLE>
<DESCRIPTION>这里是DESCRIPTION</DESCRIPTION>
</PROGRAMSLOT>
<PROGRAMSLOT>
<TIME>2008</TIME>
<TITLE>test title 222</TITLE>
</PROGRAMSLOT>
</DAY>
</CHANNEL>
</TVSCHEDULE>
三、XML解析:JAXP-dom
两种解析方式
xml 的解析技术:dom 和 sax
- dom 方式解析(Document Object Model,文档对象模型):根据 xml 的层级结构在内存中分配一个树形结构,把 xml 的标签、属性、文件都封装成对象
-
- 优点:非常方便实现做增删改操作;
- 缺点:使用 dom 方式解析 xml 时候文件很大会造成内存溢出,不能进行分配;
- sax 方式解析(Simple APl for XML,开源的):采用事件驱动,边读边解析,从上到下,一行一行的解析,解析到某一个对象返回对象名称
-
- 优点:使用 sax 方式不会造成内存溢出因为它是边读边解析,从而实现查询;
- 缺点:使用 sax 方式解析就不能实现增删改操作;
XML解析器:
- JAXP:SUN标准解析,Sun公司提供了针对dom和sax解析器叫做 jaxp
- Dom4J:开源解析开发包,针对dom和sax解析器 叫做 dom4j(用的最多)
- JDom:开源解析开发包,针对dom和sax解析器叫做 jdom
JAXP的API
包
- org.w3c.dom:提供 DOM 方式解析 XML 的标准接口
- org.xml.sax:提供 SAX 方式解析 XML 的标准接口
- javax.xml:提供了解析 XML 文档的类
javax.xml.parsers包中,定义了几个工厂类。我们可以通过调用这些工厂类,得到对XML文档进行解析的 DOM 和 SAX 解析器对象。
1、针对dom解析使用的类
DocumentBuilder :解析器类,这个类是一个抽象类,不能new
此类的实例可以从 DocumentBuilderFactory.newDocumentBuilder() 方法获取。
解析 xml:Document parse("xml路径") 。返回的 Document 是一个接口,父节点是 Node。
Document 方法:
-
- getElementsByTagName(String tagname) 这个方法可以得到标签返回集合 NodeList
- createElement(String tagName)创建标签元素
- createrTextNode(String date)创建文本
Node里面的方法:
-
- appendChild(Node newChild) 把文本添加在标签下面
- removeChild(Node oldChild) 删除节点
- getParentNode() 获取到父节点
NodeList里面的方法:
-
- getLength() 得到集合的长度
- item(int index) 根据下标取到的具体的值
DocumentBuilderFactory :解析器工厂,这个类一个抽象类,不能new
newInstance() 获取DocumentBuilderFactory的实例。
2、针对sax解析使用的类
SAXParser:解析器类,此类的实例可以从 SAXParserFactory.newSAXParser() 方法获得
SAXParserFactory:解析器工厂,抽象类,实例 newInstance() 方法得到
查询节点
package qa.music.demo25;
import org.w3c.dom.Document;
import org.w3c.dom.NodeList;
import org.xml.sax.SAXException;
import javax.xml.parsers.DocumentBuilder;
import javax.xml.parsers.DocumentBuilderFactory;
import javax.xml.parsers.ParserConfigurationException;
import java.io.IOException;
public class TestXml {
public static void main(String[] args) throws ParserConfigurationException, IOException, SAXException {
// 步骤1:创建解析器工厂
DocumentBuilderFactory factory = DocumentBuilderFactory.newInstance();
// 步骤2:根据解析器工厂创建解析器
DocumentBuilder builder = factory.newDocumentBuilder();
// 步骤3:解析XML,返回document。执行parse方法得出Document
Document document = builder.parse("src/test.xml");
// 步骤4:得到所有的name元素
NodeList names = document.getElementsByTagName("name");
// 步骤5:返回集合,遍历集合,得到每一个name元素
for (int i = 0; i < names.getLength(); i++) {
System.out.println(names.item(i).getTextContent());
}
}
}
查询某一个节点
public class TestXml2 {
public static void main(String[] args) throws ParserConfigurationException, IOException, SAXException {
// 步骤1:创建解析器工厂
DocumentBuilderFactory factory = DocumentBuilderFactory.newInstance();
// 步骤2:根据解析器工厂创建解析器
DocumentBuilder builder = factory.newDocumentBuilder();
// 步骤3:解析XML,返回document。执行parse方法得出Document
Document document = builder.parse("src/test.xml");
// 步骤4:得到所有的name元素
NodeList names = document.getElementsByTagName("name");
// 步骤5:使用下标,得到第一个元素
Node name1 = names.item(0);
System.out.println(name1.getTextContent()); // 张三
System.out.println(name1.getNodeName()); // name
}
}
添加节点
Transformer 是一个抽象类,实例需要回写TransformerFactory得到
TransformerFactory也是一个抽象类,实例是newInstance
package qa.music.demo25;
import org.w3c.dom.*;
import org.xml.sax.SAXException;
import javax.xml.parsers.DocumentBuilder;
import javax.xml.parsers.DocumentBuilderFactory;
import javax.xml.parsers.ParserConfigurationException;
import javax.xml.transform.Transformer;
import javax.xml.transform.TransformerException;
import javax.xml.transform.TransformerFactory;
import javax.xml.transform.dom.DOMSource;
import javax.xml.transform.stream.StreamResult;
import java.io.IOException;
/**
* 需求:在第一个p1下面(末尾)添加 <sex>nv</sex>
*/
public class TestXml3 {
public static void main(String[] args) throws ParserConfigurationException, IOException, SAXException, TransformerException {
// 步骤1:创建解析器工厂
DocumentBuilderFactory factory = DocumentBuilderFactory.newInstance();
// 步骤2:根据解析器工厂创建解析器
DocumentBuilder builder = factory.newDocumentBuilder();
// 步骤3:解析XML,返回document。执行parse方法得出Document
Document document = builder.parse("src/test.xml");
// 步骤4:得到所有的p1元素
NodeList list = document.getElementsByTagName("p1");
// 步骤5:使用下标,得到第一个元素
Node p1 = list.item(0);
// 步骤6:创建sex标签:createElement
Element sex = document.createElement("sex");
// 步骤7:创建文本:createTextNode
Text text = document.createTextNode("female");
// 步骤8:把文本添加到sex下面:appendChild
sex.appendChild(text);
// 步骤9:把sex添加到第一个p1下面:appendChild
p1.appendChild(sex);
// 步骤10:回写xml
TransformerFactory transformerFactory = TransformerFactory.newInstance();
Transformer transformer = transformerFactory.newTransformer();
// 这里是将XMLSource转为Result
transformer.transform(new DOMSource(document), new StreamResult("src/test.xml"));
}
}
修改节点
/**
* 需求:修改第一个p1下面的sex为 <sex>女</sex>
*/
public class TestXml4 {
public static void main(String[] args) throws ParserConfigurationException, IOException, SAXException, TransformerException {
// 步骤1:创建解析器工厂
DocumentBuilderFactory factory = DocumentBuilderFactory.newInstance();
// 步骤2:根据解析器工厂创建解析器
DocumentBuilder builder = factory.newDocumentBuilder();
// 步骤3:解析XML,返回document。执行parse方法得出Document
Document document = builder.parse("src/qa/music/demo25/test.xml");
// 步骤4:得到sex
Node sex = document.getElementsByTagName("sex").item(0);
// 步骤5:修改sex
sex.setTextContent("女");
// 步骤6:回写xml
TransformerFactory transformerFactory = TransformerFactory.newInstance();
Transformer transformer = transformerFactory.newTransformer();
transformer.transform(new DOMSource(document), new StreamResult("src/qa/music/demo25/test.xml"));
}
}
删除节点
注意:只能用父节点进行删除,不能自己删除自己
/**
* 需求:删除第二个 <age></age>
*/
public class TestXml5 {
public static void main(String[] args) throws ParserConfigurationException, IOException, SAXException, TransformerException {
// 步骤1:创建解析器工厂
DocumentBuilderFactory factory = DocumentBuilderFactory.newInstance();
// 步骤2:根据解析器工厂创建解析器
DocumentBuilder builder = factory.newDocumentBuilder();
// 步骤3:解析XML,返回document。执行parse方法得出Document
Document document = builder.parse("src/qa/music/demo25/test.xml");
// 步骤4:得到age
Node age = document.getElementsByTagName("age").item(1);
// 步骤5:得到age的父节点
Node ageParentNode = age.getParentNode();
// 步骤6:删除操作
ageParentNode.removeChild(age);
// 步骤7:回写xml
TransformerFactory transformerFactory = TransformerFactory.newInstance();
Transformer transformer = transformerFactory.newTransformer();
transformer.transform(new DOMSource(document), new StreamResult("src/qa/music/demo25/test.xml"));
}
}
遍历节点
public class TestXml6 {
public static void main(String[] args) throws Exception {
// 步骤1:创建解析器工厂
DocumentBuilderFactory factory = DocumentBuilderFactory.newInstance();
// 步骤2:根据解析器工厂创建解析器
DocumentBuilder builder = factory.newDocumentBuilder();
// 步骤3:解析XML,返回document。执行parse方法得出Document
Document document = builder.parse("src/qa/music/demo25/test.xml");
// 步骤4:调用方法,实现遍历操作
listElement(document, 0);
}
/**
* 递归遍历的方法
*
* @param node
* @throws Exception
*/
public static void listElement(Node node, int deep) throws Exception {
// 得到一层子节点
NodeList childNodes = node.getChildNodes();
// 判断如果是元素类型,则进行打印
if (node.getNodeType() == Node.ELEMENT_NODE) {
deep++;
for (int i = 1; i <= deep; i++) {
System.out.print("\t");
}
System.out.println(node.getNodeName());
}
// 遍历子节点
for (int i = 0; i < childNodes.getLength(); i++) {
// 得到每一个节点
Node node1 = childNodes.item(i);
// 继续得到node1的子节点
listElement(node1, deep);
}
}
}
四、Schema(代替DTD)
简介
XML Schema(本身是一个XML文件)是一种用于定义和描述XML文档结构与内容的模式语言,其出现是为了克服DTD的局限性(逐渐代替DTD)。特点:
- 一个XML可以有多个Schema,使用名称空间来区分;
- 支持更多数据类型,且支持自定义新的数据类型;
- 但是不能像DTD一样定义实体;
扩展名一般是用.xsd,根节点是schema
Schema开发过程
例子:
schedemo.xsd
<?xml version="1.0" encoding="UTF-8"?>
<!--xmlns:表示当前xml文件是一个约束文件,这个是固定的-->
<!--targetNamespace:此属性表示引入,通常用url地址来引入-->
<!--elementFormDefault:此属性表示质量良好-->
<schema xmlns="http://www.w3.org/2001/XMLSchema"
targetNamespace="http://www.baidu.cn/20220831"
elementFormDefault="qualified">
<element name="person"> <!--复杂元素-->
<complexType> <!--复杂类型-->
<sequence> <!--子元素顺序-->
<element name="name" type="string"></element> <!--简单元素-->
<element name="age" type="int"></element> <!--简单元素-->
<element name="sex" type="string"></element> <!--简单元素-->
<!--此子元素也是一个复杂元素-->
<element name="address">
<complexType>
<sequence>
<element name="home" type="string"></element>
<element name="company" type="string"></element>
</sequence>
</complexType>
</element>
</sequence>
</complexType>
</element>
</schema>
person.xml
<?xml version="1.0" encoding="utf-8" standalone="no"?>
<!--表示是被约束文件:-instance,等于xmlns+(-instance) -->
<!-- xmlns:xsi 起了一个别名空间叫xsi,等于targetNamespace -->
<!-- 引入约束文件{namespace}空格{location},等于targetNamespace+schema地址 -->
<person xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xmlns="http://www.baidu.cn/20220831"
xsi:schemaLocation="http://www.baidu.cn/20220831 schedemo.xsd">
<name>张三</name>
<age>20</age>
<sex>女</sex>
<address>
<home>杭州西湖区</home>
<company>杭州余杭区</company>
</address>
</person>
Schema约束API查看
schema的结构:
它的根节点是Schema,里面要加上三个属性。使用时首先要判断它是简单元素还是复杂元素,如果是一个复杂元素,先写complexType再写sequence然后再写上子元素。如果是简单元素就直接写element。
复杂元素指示器:
:表示元素的出现的顺序
:表示所有元素都只能出现一次
:表示只能出现其中一个
:表示任意配置的元素
maxOccurs="unbounded"(加在element上):表示元素出现次数没限制
在Schema里可以约束属性(必须是复杂元素,写在结束标签之前)
<attribute nane="id1" type="int" use="required">name
①name:属性名称
②type:属性类型 int stirng
③use:属性是否必须出现 required
xmlns:xsi 是加一个名称空间
例子:
<?xml version="1.0" encoding="UTF-8"?>
<schema xmlns="http://www.w3.org/2001/XMLSchema"
targetNamespace="http://www.baidu.cn/20220831"
elementFormDefault="qualified">
<element name="note">
<complexType>
<sequence>
<element name="to" type="string"/>
<element name="from" type="string"/>
<element name="heading" type="string"/>
<element name="body" type="string"/>
</sequence>
</complexType>
</element>
</schema>
<?xml version="1.0" encoding="utf-8" ?>
<note xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xmlns="http://www.baidu.cn/20220831"
xsi:schemaLocation="http://www.baidu.cn/20220831 message.xsd">
<to>George</to>
<from>Mikel</from>
<heading>meeting remember</heading>
<body>Please Don't forget!</body>
</note>
sax解析过程
SAXParser:解析器类,此类的实例可以从 SAXParserFactory的newSAXParser() 方法获得
SAXParserFactory:解析器工厂,抽象类,实例 newInstance() 方法得到
SAXParser里面的解析方法:
parse(File f, DefaultHandler dh)
参数为:File为xml的路径、DefaultHandler为事件处理器(默认的API处理器,相当于在方法里面绑定了一个事件)
DefaultHandler里面的方法:
(1)startElement()
startElement(String uri, String localName, String qName, Attributes attributes) 接收元素开始的通知
参数qName:返回标签名称
(2)endDocument()
endElement(String uri, String localName, String qName) 接收元素结束的通知
通过string的构造方法返回内容
(3)characters
characters(char [] ch, int start, int length) 接收元素中字符数据的通知,就是文本的内容
参数qName:返回标签名称
使用schema的sax方式操作xml
sax方式不能实现增删改操作,只能做查询操作
例子:
public class TestSax {
public static void main(String[] args) throws Exception {
// 1、创建解析器工厂
SAXParserFactory saxParserFactory = SAXParserFactory.newInstance();
// 2、创建解析器
SAXParser saxParser = saxParserFactory.newSAXParser();
// 3、执行parse方法,DefaultHandler里面的方法就会自动去执行
// 输出整个文档
saxParser.parse("src/p1.xml", new MyDefaultHandler());
// 输出name元素的值
saxParser.parse("src/p1.xml", new MyDefaultHandler2());
}
}
/*打印整个文档*/
public 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元素的值*/
public class MyDefaultHandler2 extends DefaultHandler {
boolean flag = false;
int index = 1;
@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 && index == 2) {
System.out.println(new String(ch, start, length));
flag = false;
}
}
@Override
public void endElement(String uri, String localName, String qName) throws SAXException {
if ("name".equals(qName)) {
flag = false;
index++; // 这个name结束,索引需要加一
}
}
}
五、XML解析:dom4j(重点)
概述
jar包下载地址:dom4j.github.io/
基本使用
解析XML
import java.net.URL;
import org.dom4j.Document;
import org.dom4j.DocumentException;
import org.dom4j.io.SAXReader;
public class Foo {
public Document parse(URL url) throws DocumentException {
SAXReader reader = new SAXReader();
Document document = reader.read(url);
// 返回document,更加方便
return document;
}
}
使用迭代器
public void bar(Document document) throws DocumentException {
Element root = document.getRootElement();
// iterate through child elements of root
for (Iterator<Element> it = root.elementIterator(); it.hasNext();) {
Element element = it.next();
// do something
}
// iterate through child elements of root with element name "foo"
for (Iterator<Element> it = root.elementIterator("foo"); it.hasNext();) {
Element foo = it.next();
// do something
}
// iterate through attributes of root
for (Iterator<Attribute> it = root.attributeIterator(); it.hasNext();) {
Attribute attribute = it.next();
// do something
}
}
XPath导航
public void bar(Document document) {
List<Node> list = document.selectNodes("//foo/bar");
Node node = document.selectSingleNode("//foo/bar/author");
String name = node.valueOf("@name");
}
例如在在XHTML文档中找到所有超文本链接:
public void findLinks(Document document) throws DocumentException {
List<Node> list = document.selectNodes("//a/@href");
for (Iterator<Node> iter = list.iterator(); iter.hasNext();) {
Attribute attribute = (Attribute) iter.next();
String url = attribute.getValue();
}
}
创建新的XML文档
import org.dom4j.Document;
import org.dom4j.DocumentHelper;
import org.dom4j.Element;
public class Foo {
public Document createDocument() {
Document document = DocumentHelper.createDocument();
Element root = document.addElement("root");
Element author1 = root.addElement("author")
.addAttribute("name", "James")
.addAttribute("location", "UK")
.addText("James Strachan");
Element author2 = root.addElement("author")
.addAttribute("name", "Bob")
.addAttribute("location", "US")
.addText("Bob McWhirter");
return document;
}
}
将文档写入文件
FileWriter out = new FileWriter("foo.xml");
document.write(out);
out.close();
查询XML
package qa.music.demo27;
import org.dom4j.Document;
import org.dom4j.Element;
import org.dom4j.io.SAXReader;
import java.util.List;
public class TestDom4j {
public static void main(String[] args) throws Exception {
//selectName();
//selectFirst();
selectSecond();
}
/**
* 查询xml中所有name元素的值
*/
public static void selectName() throws Exception {
// 1.创建解析器
SAXReader saxReader = new SAXReader();
// 2.得到document
Document document = saxReader.read("src/p1.xml");
// 3.得到根节点
Element rootElement = document.getRootElement();
// 4.得到p1
List<Element> p1list = rootElement.elements("p1");
// 5.遍历list,用增强for循环
for (Element element : p1list) {
// 6.得到p1下面的name
Element name = element.element("name");
// 7.得到name里面的值
System.out.println(name.getText());
}
}
/**
* 查询第一个name元素的值
*/
public static void selectFirst() throws Exception {
SAXReader saxReader = new SAXReader();
Document document = saxReader.read("src/p1.xml");
Element rootElement = document.getRootElement();
// 得到第一个p1
Element p1 = rootElement.element("p1");
// 得到p1下面的name元素
Element name = p1.element("name");
System.out.println(name.getText());
}
/**
* 查询第二个name元素的值
*/
public static void selectSecond() throws Exception {
SAXReader saxReader = new SAXReader();
Document document = saxReader.read("src/p1.xml");
Element rootElement = document.getRootElement();
// 得到所有p1
List<Element> p1list = rootElement.elements("p1");
// 得到第二个name
Element name = p1list.get(1).element("name");
System.out.println(name.getText());
}
}
末尾添加节点
public class TestDom4j2 {
public static void main(String[] args) throws Exception {
addSex();
}
/**
* 第一个p1标签末尾添加一个元素<sex>nv</sex>
*/
public static void addSex() throws Exception {
// (1) 创建解析器
SAXReader saxReader = new SAXReader();
// (2) 得到document
Document document = saxReader.read("src/p1.xml");
// (3) 得到根节点
Element rootElement = document.getRootElement();
// (4) 获取到第一个p1
Element p1 = rootElement.element("p1");
// (5) 在p1下面添加元素
Element sex = p1.addElement("sex");
// (6) 在添加完成之后的元素下面添加文本
sex.setText("male");
// (7) 回写xml(因为是对xml文件内进行操作)
OutputFormat format = OutputFormat.createPrettyPrint(); // 格式化
XMLWriter xmlWriter = new XMLWriter(new FileOutputStream("src/qa/music/demo27/p1.xml"), format);
xmlWriter.write(document);
xmlWriter.close();
}
}
特定位置添加节点
public class TestDom4j3 {
public static void main(String[] args) throws Exception {
addAgeBefore();
}
/**
* 第一个p1下面的age标签之前添加<school>国防科技大学</school>
*/
public static void addAgeBefore() throws Exception{
// 创建解析器
SAXReader saxReader = new SAXReader();
// 得到document
Document document = saxReader.read("src/p1.xml");
// 得到根节点
Element rootElement = document.getRootElement();
// 获取到第一个p1
Element p1 = rootElement.element("p1");
// 获取p1下面的所有的元素
List<Element> list = p1.elements();
// 创建元素在元素下面创建文本
Element school = DocumentHelper.createElement("school");
school.setText("国防科技大学");
// 使用list里面的方法,在特定位置添加元素
list.add(1, school);
// 回写xml
OutputFormat format = OutputFormat.createPrettyPrint(); // 格式化
XMLWriter xmlWriter = new XMLWriter(new FileOutputStream("src/qa/music/demo27/p1.xml"), format);
xmlWriter.write(document);
xmlWriter.close();
}
}
\
常用代码封装
public class Dom4jUtil {
/**
* 解析返回Document
* @param path xml文件路径
* @return Document
* @throws Exception
*/
public static Document parse(String path) throws Exception{
// 创建解析器
SAXReader saxReader = new SAXReader();
// 得到document
Document document = saxReader.read(path);
return document;
}
/**
* 回血XML
* @param path xml文件路径
* @param document Document
* @throws Exception
*/
public static void xmlWriters(String path, Document document) throws Exception{
OutputFormat format = OutputFormat.createPrettyPrint(); // 格式化
XMLWriter xmlWriter = new XMLWriter(new FileOutputStream(path), format);
xmlWriter.write(document);
xmlWriter.close();
}
}
测试工具类:
public class TestDom4j5 {
public static void main(String[] args) throws Exception {
demo();
}
/**
* 查询xml中所有name元素的值
*/
public static void demo() throws Exception {
Document document = Dom4jUtil.parse("src/p1.xml");
Element rootElement = document.getRootElement();
Element p1 = rootElement.element("p1");
Element sex = p1.addElement("address");
sex.setText("浙江杭州");
Dom4jUtil.xmlWriters("src/p1.xml", document);
}
}
修改节点
public class TestDom4j6 {
public static void main(String[] args) throws Exception {
Document document = Dom4jUtil.parse(Dom4jUtil.PATH);
Element rootElement = document.getRootElement();
Element p1 = rootElement.element("p1");
Element age = p1.element("age");
age.setText("88");
Dom4jUtil.xmlWriters(Dom4jUtil.PATH, document);
}
}
\
删除节点
public class TestDom4j7 {
public static void main(String[] args) throws Exception {
Document document = Dom4jUtil.parse(Dom4jUtil.PATH);
Element rootElement = document.getRootElement();
Element p1 = rootElement.element("p1");
Element address = p1.element("address");
p1.remove(address);
Dom4jUtil.xmlWriters(Dom4jUtil.PATH, document);
}
}
\
获取属性值
public class TestDom4j8 {
public static void main(String[] args) throws Exception {
Document document = Dom4jUtil.parse(Dom4jUtil.PATH);
Element rootElement = document.getRootElement();
Element p1element = rootElement.element("p1");
// 获取p1里面的属性值
String id = p1element.attributeValue("id");
System.out.println(id);
}
}
\
\
六、XPATH
简介
一个/表示一层:
- /aaa 表示第一层,第一层aaa就可以取到
- /aaa/ccc 表示aaa层下面的ccc(某一层下面的所有某元素)
- /aaa/ddd/bbb 表示aaa下面的ddd的bbb元素
两个/表示任意层:
- //bbb 表示:和这个名称相同,只要名称是BBB都可以得到,不管在哪层
- //ddd/bbb 表示所有DDD下面的BBB都得到
"*"表示所有元素:
- /aaa/ccc/ddd* 表示aaa中的ccc中的ddd里面的所有元素
- ///*/bbb 表示前三层下的bbb元素
- //* 表示所有的元素
[]表示坐标索引的元素:
- /aaa/bbb[1] 表示aaa元素里的第一个bbb
- /aaa/bbb[last()] 表示表示aaa元素里的最后一个bbb
@表示带有某属性的元素:
- //@id 表示只要标签上有id属性都可以得到
- //bbb[@id] 表示只要bbb上面有id属性都可以得到
- //bbb[@id='b1'] 表示元素名称是bbb,在bbb元素里面有id属性,id的值是b1
- //aaa[@name='bbb'] 表示aaa下面有name属性,name的值是bbb
dom4j的XPATH操作
jaxen的jar包下载地址:www.java2s.com/Code/Jar/j/…
支持xpath的方法:
- selectNodes("xpath表达式") ---获取多个节点
- selectSingleNode(“xpath表达式”) ---获取一个节点
public class TestDom4j9 {
public static void main(String[] args) throws Exception {
Document document = Dom4jUtil.parse(Dom4jUtil.PATH);
// 得到所有的name元素
List<Node> nodeList = document.selectNodes("//name");
for (Node node : nodeList) {
System.out.println(node.getText());
}
}
}
public class TestDom4j10 {
public static void main(String[] args) throws Exception {
Document document = Dom4jUtil.parse(Dom4jUtil.PATH);
// 获取第一个p1下面的name属性
Node node = document.selectSingleNode("//p1[@id='aaa']/name");
System.out.println(node.getText());
}
}
七、学生管理系统案例
student.xml
<student>
<stu>
<id>100</id>
<name>ZhangSan</name>
<age>20</age>
</stu>
<stu>
<id>101</id>
<name>LiSi</name>
<age>21</age>
</stu>
</student>
功能类:
public class StuService {
/**
* 增加学生
*
* @param student
* @throws Exception
*/
public static void addStu(Student student) throws Exception {
Document document = Dom4jUtil.parse(Dom4jUtil.PATH);
// 得到根节点
Element rootElement = document.getRootElement();
// 在根节点上面添加stu
Element stu = rootElement.addElement("stu");
// 在stu标签上面依次添加id name age标签 和对应的值
Element id = stu.addElement("id");
id.addText(student.getId());
Element name = stu.addElement("name");
name.addText(student.getName());
Element age = stu.addElement("age");
age.addText(student.getAge());
// 回写xm1
Dom4jUtil.xmlWriters(Dom4jUtil.PATH, document);
}
/**
* 删除学生
* @param id
* @throws Exception
*/
public static void deleteStu(String id) throws Exception {
Document document = Dom4jUtil.parse(Dom4jUtil.PATH);
// 获取所有的id,xpath: //id
List<Node> list = document.selectNodes("//id");
for (Node node : list) {
if (id.equals(node.getText())) {
// 得到stu节点
Element stu = node.getParent();
// 获取stu的父节点,删除这个id的整个stu
Element parent = stu.getParent();
parent.remove(stu);
}
}
// 回写xm1
Dom4jUtil.xmlWriters(Dom4jUtil.PATH, document);
}
/**
* 查询学生
* @param id
* @return Student
* @throws Exception
*/
public static Student getStu(String id) throws Exception {
Student student = null;
Document document = Dom4jUtil.parse(Dom4jUtil.PATH);
// 获取所有的id,xpath: //id
List<Node> list = document.selectNodes("//id");
for (Node node : list) {
if (id.equals(node.getText())) {
// 得到id的父节点stu
Element stu = node.getParent();
// 通过stu获取name和age
String name = stu.element("name").getText();
String age = stu.element("age").getText();
student = new Student(id, name, age);
}
}
return student;
}
}