二、 XML
2.1 XML 简介
XML 是 Extensible Markup Language 的缩写,即可扩展标记语言,是一种简单的数据存储语言,使用一系列简单的标记来描述结构化数据。
- XML的特点:
- XML与操作系统,编辑语言的开发平台都无关。
- 规范统一,实现不同系统之间的数据交互。
2.1.1 XML 的文档结构
xml
<?xml version="1.0" encoding="UTF-8"?>
<books>
<!--图书信息-->
<book id="bk101">
<title>.NET 高级编程</title>
<author>王珊</author>
<description>包含C#框架和网络编程等</description>
</book>
<book id="bk102">
<title>XML 基础编程</title>
<author>李明明</author>
<description>包含 XML 基础概念和基本用法</description>
</book>
</books>
2.1.2 XML 声明
<?xml version="1.0" encoding="UTF-8"?> 表示XML声明,用以表名该文件是一个 XML 文档
- XML 声明由以下几部分组成
- version:文档符合 XML 1.0 规范。
- encoding:文档字符编码,默认为"UTF-8"。
- 对于任何一个 XML 文档,其声明部分都是固定格式。
2.1.3 标签
- 在XML中,通过尖括号<>括起来的各种(Tag)来标记数据。
- **标签必须成对使用,必须有开始标签
<>
和 结束标签</>**
- 标签成对使用来界定字符数剧。
注意:XML 标签必须正确结束并正确地嵌套,缺少结束标签及如下的嵌套方式是错误的。
xml<title> <name> XML 编程 </name> </title>
2.1.4 元素
-
XML 文档的主要部分是元素,如"王珊"就是一个元素。
-
元素由开始标签、结束标签和元素内容组成。
-
元素命名规则如下:
- 名称中可以包含字母、数字或其他的符号。
- 名称不能以数字或标点符号开始。
- 名称不能以字符"xml"(或XML、Xml)开始。
- 名称中不能包含空格
-
元素允许是空元素,如的元素写法是允许的。
2.1.5 根元素
每一个XML文档必须有且仅有一个根元素,如""。
- 根元素的特点:
- 根元素是一个完全包括文档中其他所有元素的元素。
- 根元素的起始标签要放在所有其他元素的起始标签之前。
- 根元素的结束标签要放在其他元素的结束标签之后。
2.1.6 属性
- 语法:
xml
<元素名 属性名="属性值">
- 属性值同双引号包裹。
注意:
- 一个元素可以有多个属性,多个属性之间用空格隔开,
格式:
xml<元素名 属性名="属性值" 属性名="属性值"/>
- 属性值中不能直接包含<、"、&。
- 属性可以加载任何一个元素的起始标签上,但不能加在结束标签上。
2.1.7 XML 中的特殊字符的处理
- 在 XML 中,有时在元素的文本中会涉及一些特殊字符
<
>
'
"
&
- 使用这些字符,需要用到 XML 中的预定义实体代替
- XML 中的预定义实体和特殊字符的对应关系
特殊字符 | 实体名称 |
---|---|
< | < |
> | > |
& | & |
" | " |
' | ' |
2.1.8 格式良好的XML文档
- 格式良好的XML文档需要遵循如下规则:
- 有XML声明语句。
- 有且仅有一个根元素。
- 标签大小写敏感。
- 属性值用双引号包裹。
- 标签成对/空标签关闭。
- 元素正确嵌套。
2.2 解析 XML 概述
在实际应用中,经常需要对 XML 文档进行各种操作
如应用程序启动时去读取 XML 文档配置文件信息
或者把数据库中的内容读取出来转换成 XML 文档形式
这些时候都会用到 XML 文档的解析技术
目前常用的 XML 解析技术有 4 种
2.2.1 DOM
- DOM 是基于 XML 的树结构来完成解析的
- DOM 解析 XML 文档时,会根据读取的文档,构建一个驻留内存的树结构
- 然后就可以使用 DOM API 来操作这个数结构
- 因为整个文档的树结构是驻留在内存中的,所以非常方便各种操作
- 支持删除、修改、重新排列等
- 但 DOM 解析却是比较消耗资源的
2.2.2 SAX
- SAX 是基于事件的解析,为了解决 DOM 解析的资源消耗而出现的
- SAX 解析不用实现调用整个文档,所以占用资源少、内存消耗小
- 一般在解析数据量较大的 XML 文档时会采用 SAX 方式
2.2.3 JDOM
- DOM 是不针对语言的,而 JDOM 是针对 Java 的特定文档模型
- 简化了与 XML 的交互并且比使用 DOM 更快
- JDOM 仅使用具体类而不使用接口,这在某些方面简化了 API
- JDOM 的优势在于 "使用20%的精力解决80%的Java/XML问题"
2.2.4 DOM4J
- DOM4J 是一个非常优秀的 Java XML API,具有性能优异、功能强大和易用的特点。
2.3 使用 DOM 读取 XML 数据
2.3.1 DOM概念
DOM 是 Document Object Model 的简称,即文档对象模型
DOM 把 XML 文件映射成一颗倒挂的"树"
以根元素为节点,每个节点都以对象形式存在
- 创建文件 book.xml
xml
<?xml version="1.0" encoding="UTF-8"?>
<book>
<title>三国演义</title>
<author>罗贯中</author>
<price>30元</price>
</book>
- book.xml 文档对应的 DOM 树结构:
根元素book 元素:title 元素:author 元素:price 文本:三国演义 文本:罗贯中 文本:30元
2.3.2 使用 DOM 读取手机信息
- org.w3c.dom:W3C 推荐的用于使用 DOM 解析 XML 文档的接口
- org.xml.sax:用于使用 SAX 解析 XML 文档的接口。
- javax.xml.parsers:解析器工厂工具,获得并配置特殊的分析器。
- 创建解析器工厂对象,即 DocumentBuilderFactory 对象。、
- 由解析器工厂对象创建解析器对象,即 DomentBuilder 对象。
- 由解析器对象对指定的 XML 文件进行解析,构建相应的 DOM 树,创建 Document 对象。
- 以 Document 对象为起点对 DOM 树的节点进行增加、删除、修改、查询等操作。
xml
<?xml version="1.0" encoding="UTF-8" ?>
<PhoneInfo>
<Brand name="华为">
<Type name="P90"/>
</Brand>
<Brand>
<Type name="iPhone Z"/>
<Type name="iPhone ZL"/>
</Brand>
</PhoneInfo>
java
//得到 DOM 解析器的工厂实例
DocumentBuilderFactory builderFactory = DocumentBuilderFactory.newInstance();
//从 DOM 工厂获得 DOM 解析器
DocumentBuilder documentBuilder = builderFactory.newDocumentBuilder();
//解析 XML 文档,得到一个 Document 对象,即 DOM 树
Document document = documentBuilder.parse("src/main/java/CH02XML/sumUP/bookInfo.xml");
//得到所有 Brand 节点列表信息
NodeList brandList = document.getElementsByTagName("Brand");
//循环 Brand 信息
for (int i = 0; i < brandList.getLength(); i++) {
//获取第 i 个Brand 元素信息
Node brand = brandList.item(i);
//获取第 i 个 Brand 元素的 name 属性值
Element element = (Element) brand;
String attrValue = element.getAttribute("name");
//获取第 i 个 Brand 元素的所有子元素的 name 属性值
NodeList types = element.getChildNodes();
for (int j = 0; j < types.getLength(); j++) {
if (types.item(j).getNodeType() == 1) {
Element typeElement = ((Element) types.item(j));
String type = typeElement.getAttribute("name");
System.out.println("手机:" + attrValue + type);
}
}
}
- Node对象
Node 对象是 DOM 结构中最基本的对象,代表了文档树中的一个抽象节点。
- getChildNodes():返回包含此节点所有的子节点的 NodeList。
- getFirstChild():如果节点存在子节点,则返回第一个子节点。
- getLastChild():如果节点存在子节点,则返回最后一个子节点。
- getNextSibling():返回在 DOM 树中这个节点的下一个兄弟节点。
- getPreviousSibling():返回在 DOM 树中这个节点的上一个兄弟节点。
- getNodeName():返回节点的名称。
- getNodeValue():返回节点的值。
- getNodeType():返回节点的类型。
- NodeList 对象
NodeList 对象是指包含了一个或多个节点(Node)的列表。
可以简单地把它看成一个 Node 数组,也可以通过方法来获得列表中的元素,
-
NodeList 对象的常用方法:
-
getLength():返回列表的长度。
-
item(int index):返回指定位置的 Node 对象。
-
- Document 对象
Document 对象代表整个 XML 文档,
所有其他的 Node 都以一定的顺序包含在 Document 对象之内
排列成一个树状结构,可以通过遍历这颗"树"来得到 XML 文档的所有内容。
它也是对XML文档进行操作的起点。
- Docuemnt 对象方法如下
- getElementsByTagName(String name):返回一个 NodeList 对象,它包含了所有给定标签的标签。
- getDocumentElement():返回一个代表这个 DOM 树的根节点的 Element 对象,也就是代表 XML 文档根元素的对象。
- Element 对象
Element 对象代表 XML 文档中的标签元素,继承自 Node,也是 Node 最主要的子对象,也就是代表 XML 文档根元素的对象。
- 方法如下:
- getAttribute(String attributename):返回标签中给定属性名称的属性的值。
- getElementsByTagName(String name):返回具有给定标签名称的所有后代 Element 的 NodeList。
注意:
- 使用 Element 的 getElementsByTagName(String name),返回的 NodeList 就是所期待的对象,然后使用 item() 方法提取。
- 调用 Node 的getChildNodes() 方法得到 NodeList 对象,每次通过 item() 方法提取 Node 对象后判断 node.getNodeType()==Node.ELEMENT_NODE,即判断是否是元素节点,如果为 true,则是
2.4 使用 DOM4J 解析 XML
2.4.1 DOM4J API 概述
- Attribute:定义了 XML 的属性
- Branch:为能够包含子节点的节点。
- CDATA:定义了 XML CDATA 区域。
- CharacterData:是一个标识接口,标识基于字符的节点,如CDATA、Comment 和 Text。
- Comment:定义了 XML 注释的行为。
- Document:定义了 XML 文档。
- DocumentType:定义了 XML DOCTYPE 声明。
- Element:定义 XML 元素。
- ElementHandler:定义了 Element 对象的处理器。
- ElementPath:被ElementHandler 使用,用于取得当前正在处理的路径层次信息。
- Entity:定义 XML 实体。
- Node:为 dom4j 中的所有 XML 节点定义了多态行为。
- NodeFilter:定义了在 dom4j 节点中产生的一个滤镜或谓词(Predicate)的行为。
- ProcessingInstruction:定义 XML 处理指令。
- Text:定义 XML 文本节点。
- Visitor:用于实现 Visitor 模式。
- Xpath:通过分析一个字符提供了一个 XPath 表达式。
2.4.2 使用 DOM4J 操作 XML 数据
要使用 DOM4J 读写 XML 文档,需要先下载 dom4j 的 jar 包,在 https://dom4j.github.io 下载后将相应的 jar 包加入工程就可以使用了,
-
Document 对象相关
- 读写XML文件,获得 Document 对象。
javaSAXReader reader=new SAXReader(); Document document=reader.read(new File("input.xml"));
-
节点相关
- 获取文档的根元素
javaElement rootElm=document.getRootElement();
- 取得某节点的单个子节点。
javaElement memberElm=rootElm.element("member");//member是节点名
- 取得节点的文字
javaString text=memberElm.getText();
- 取得某节点下名为 "member" 的所有子节点并进行遍历。
javaList nodes=rootElm.elements("member"); for(Iterator it=nodes.iterator(); it.hasNext();){ ELement elm=(Element) it.next(); }
- 在某节点下添加子节点。newMemberElm 是某个已存在的节点。
javaElement ageElm=newMemberElm.addElement("age");
- 设置节点文字。
jabaageElm.setText("29");
- 删除某节点
javaparentElm.remove(childElm);//childEle 是待删除的节点,parentElm 是其父节点
-
属性相关
- 取得某节点下的某属性。
javaElement root=document.getRootElement(); Attribute attribute=root.attribute("size");//size 属性名
- 取得属性的值
javaString text=attribute.Text();
- 遍历节点的所有属性。
javaElement root=document.getRootElement(); for(Iterator it=root.attributeIterator();it.hasNext()){ Attribute attribute=(Attribute)it.next(); String text=attribute.getText(); System.out.println(texxt); }
- 为其节点添加属性。
javanewMemberElm.addAttribute("name","learningdom4j");
- 设置属性的值。
javaAttribute attribute=root.attribute("name"); attribute.setText("learningdom4j");
- 删除某属性
javaAttribute attribute=root.attribute("size"); root.remove(attribute);
-
将文档写入 XML 文件
- 文档中全为英文,不设置编码格式,直接写入
javaXMLWriter writer=new XMLWriter(new FileWriter("output.xml")); writer.write(document); writer.close();
- 文档中含有中文,设置编码格式在写入。
javaOutputFormat format=OutputFormat.createPrettyPrint(); format.setEncoding("GBK"); //指定 XML 编码 XMLWriter writer=new XMLWriter(new FileWriter("output.xml")); writer.write(document); writer.close();
将文档写入 XML 文件*
- 文档中全为英文,不设置编码格式,直接写入
java
XMLWriter writer=new XMLWriter(new FileWriter("output.xml"));
writer.write(document);
writer.close();
- 文档中含有中文,设置编码格式在写入。
java
OutputFormat format=OutputFormat.createPrettyPrint();
format.setEncoding("GBK"); //指定 XML 编码
XMLWriter writer=new XMLWriter(new FileWriter("output.xml"));
writer.write(document);
writer.close();