XML
XML定义
XML, Extensible Markup Language(可扩展标记语言),由SGML语言发展而来,允许用户自定义标签,可以将标签和内容有效分离。它逐渐演变为—种跨平台的数据交换格式(一种在不同平台、不同系统之间的数据交换格式),一种轻量级的持久化方案(保存简单数据,无需使用数据库)。XML只是纯文本而已,只是一种独立于软件、硬件的数据存储和传输工具。它可对外提供一下信息,但于C、Java这些编程语言不同,XML无法提供任何“动态行为”。和HTML提供预定义标签不同,开发者可以自定义任意标签,因此具有很强的扩张性不同于HTML侧重于数据的展示,XML更加关注数据的存储和传输;不同于HTML可以使用浏览器来解析并显示,XML需自行编写软件或程序,才能传送、接收、显示这个文档。1998年2月10日,XML正式成为W3C的推荐标准(晚于HTML)。XML和 Javaee是两种不同的技术,但是其广泛的用在 Javaee开发的各个方面,比如使用XML作为配置文件,使用XML进行数据交换。
XML文档的优缺点
优点:
- 简单性
逍循XML文档的基本规则的前提下,可以任意自定义标签 - 良好的可读性
遵循XML文档的基本规则的前提下,标签名见名知义,具有良好的嵌套关系,带有了良好的可读性。 - 可扩展性
可以根据XML的基本语法来进一步限定使用范围和文档格式,从而定义一种新的语言 - 可以轻松的跨平台应用
XML文档是基于文本的,所以很容易被人和机器阅读,也非常容易使用,便于不同设备和不同系统间的信息交换 - 数据内容与显示的分离
在XML文档中,数据的显示样式已从文档中分离出来,而放入相关的样式表文件中
XML的组成
XML文档有以下几部分组成。
文档声明
XML文档必须以文档声明开始,声明中包含了:version文档版本号,encoding文档编码格式。
<?xml version="1.0" encoding="utf-8" ?>
元素
XML文档必须包含元素,每一对标签即为一个元素,元素通常为以开始标签、元素内容、结束标签组成,并且开始标签名需要和结束标签同名。元素必须拥有结束标签,但是可以没有开始标签和内容。元素中的每一个子标签也是一个元素,元素是XML文档的主要部分,一个XML文档只能有一个根元素,作为所有元素的根。XML的元素对大小写敏感,大小写不同的标签被视为两个不同的元素。
<Users>...内容...</Users>
属性
XML文档中的标签可以有属性也可以没有属性,属性用来描述元素。属性必须写在元素的开始标签上,元素的属性没有先后顺序,属性名自定义,属性值必须使用双引号,每一个元素可以有众多属性,同一个元素中属性名是唯一的不可重复,
<user id="001"></user>
特殊符号
由于XML文档使用了部分字符作为关键字符。我们不能以正常的方式书写这些符号,这样会导致符号被当做关键符进行解析。以下列出了两种解决方式。
字符实体
如果我们要少量使用这些字符则需要使用XML文档规定的一些其他字符来代替,以确保XML中的这些字符可以被正确解析。
原始字符 | 代替字符 |
---|---|
<; | < |
>; | > |
&; | & |
&apos | ’ |
" | " |
注释:在 XML 中,只有字符 “<” 和 “&” 确实是非法的。大于号是合法的,但是用实体引用来代替它是一个好习惯。
CTATA
CTATA为:CharData的缩写
在使用大量的关键字符时可以使用CTATA来包裹这些字符,以保证符号被正确的解析。
CDATA 部分中的所有内容都会被解析器忽略。
CDATA 部分不能包含字符串 “]]>”。也不允许嵌套的 CDATA 部分。
标记 CDATA 部分结尾的 “]]>” 不能包含空格或换行。
<user><![CDATA[ “符号”]]>/user>
注释
在XML文档中使用 <!--注释内容 -->
进行注释说明。
XML文档规范
-
元素正确嵌套XML
-
文件的第一行必须是XML声明
-
XML文件只能有一个根节点
-
英文字符的大小写是有差异的
-
开始的控制标记与结束的控制标记缺一不可
-
属性值的设置必须被"包围起来
有效的XML文档
- 首先必须是格式良好的(语法约束)
- 使用DTD和XSD( XML Schema)定义语义约束
DDT约束
TD, Document Type Definition,文档类型定义,保证ⅩML文档格式正确性。使用DTD定义了合法的语义约束后,必须让XML文档引入该语义约束,才会生效。在ⅩM文档中引入DTD主要包括3中方式:
- 内部DTD
- 外部DTD
- 公用DTD
符号说明
(!!不包含全部)
-
子元素有序使用逗号:<! ELEMENT user( name, age, sxe)>。
-
子元素互斥使用竖线:<! ELEMENT user( name age,sxe)>。
-
子元素无序没有特殊语法,变通解决:<! ELEMENT user(name| age|sxe)+>。
-
元素类型:字符串类型# PCDATA空内容 EMPTY、任意内容ANY、子元素。
-
子元素出现的频率
?
表示子元素出现0次到1次令。
+
表示子元素至少出现一次。
*
表示子元素可以出现0到多次。 -
PCDATA: (parsed character data)被解析的字符串类型在DTD定义来指定元素类型 CDATA (character data)不被解析的字符串类型在DTD定义中指定属性类型。
-
ATTLIST只能定义一个属性,如果个元素包括多个属性,需通过多个 ATTLIST来定义。
内部DTD
内部DTD是指DTD和XML数据在同一个XML文件中。DTD定义在XML声明和XML主体内容之间。以 <! DOCTYPE " 根元素" [
开始,....约束规则....
以 ]>
结束
示例:
<?xml version="1.0" encoding="utf-8" ?><!-- 文档声明 -->
<!DOCTYPE Users [
<!--声明根元素下的子元素,“+”表示至少可以有一个这样的子元素-->
<!ELEMENT Users (user+)>
<!--声明根元素下user子元素可拥有那些子元素-->
<!ELEMENT user (name,age,sxe)>
<!--声明属性的约束,为id属性 声明为普通文本,且值不能为空-->
<!ATTLIST user id CDATA #REQUIRE>.
<!--声明name元素的属性为没有属性-->
<!ELEMENT name (#PCDATA)>
<!--声明age元素的属性为没有属性-->
<!ELEMENT age (#PCDATA)>
]>
<Users>
<user id="001">
<name>张三</name>
<age>19</age>
</user>
</Users>
外部DTD
在不同的XML文件使用相同的DTD验证规则时,使用内部DTD就会导致代码的重复,不利于后期修改维护。此时可以定义外部DTD,让XML文件来引入外部DTD达到可复用的效果。在DTD中定义语义约束简单易用,但是也具有一些明显的劣势:DTD可以定义XM文档的结构,却无法对ⅩML元素内容进行约束,比如,如果希望某个XML元素的内容是日期类型,希望内容必须是正整数,希望某个子元索最多出现3次,就无能为力了。这就需要使用 XML Schema来进行语义约束了。
1.创建一个.dtd
文件,将DTD约束写入此文件中。
<!DOCTYPE Users [
<!--声明根元素下的子元素,“+”表示至少可以有一个这样的子元素-->
<!ELEMENT Users (user+)>
<!--声明根元素下user子元素可拥有那些子元素-->
<!ELEMENT user (name,age)>
<!--声明属性的约束,为id属性 声明为普通文本,且值不能为空-->
<!ATTLIST user id CDATA #REQUIRE>
<!--声明name元素的属性为没有属性-->
<!ELEMENT name (#PCDATA)>
<!--声明age元素的属性为没有属性-->
<!ELEMENT age (#PCDATA)>
]>
2.在XML文件中引入此约束。
语法格式:<!DOCTYPE 根元素 SYSTEM "外部约束路径.dtd">
<?xml version="1.0" encoding="utf-8" ?><!-- 文档声明 -->
<!--引入外部dtd约束-->
<!DOCTYPE Users SYSTEM "Users.dtd">
<Users>
<user id="001">
<name>张三</name>
<age>19</age>
</user>
</Users>
XML Schema约束
DTD和 XML Schema是两种XML定义语义约束的工具,二者各有特色:DTD简单易用,但是功能相对较弱。XML Schema采用XML文档来定义语义约束,要复杂一些,但是功能强大的多。 XML Schema指定丰富的类型,而且允许开发者自定义数据类型,因此完全可以处琿更加复杂的语义约束场景XML。
Schema简称 XSD(XML Schema Definition),是DTD的替代者,既可以定义XML文档结构,也可以定义ⅩML文档的内容约束。优势体现在:
-
令可读性强:
本身就是一个XML文档 -
支持数据类型:
比如日期类型,并且限制日期范围都没有问题 -
可扩展:
导入其他的 Schema,自定义数据类型、一个ⅩML文档使用多个XML Schema 。
JavaEE和JavaEE开源框架中都大量使用了XML文档,其语义约束也己经陆续从之前的DTD约束升级为 Schema约束。
使用DOM4J解析XML文档
DOM4J的操作原理类似于DOM树。请遵循DOM树的思想使用。
注意
DOM4J解析XML文档的默认路径为项目的 resources
目录下,在不修改默认读取位置情况下,读取非resources目录下的XML文档很可能发生文件找不到异常,此异常来自于DOM4J,而不是流。
对于创建XML文档文件时则没有位置要求,但如果不将新创建的XML文档文件创建在resources
目录下,在读取此文件时则依然很可能发生文件找不到异常,此异常来自于DOM4J,而不是流。
解析
- 在使用maven或下载DOM4J的jar包。
<dependency>
<groupId>dom4j</groupId>
<artifactId>dom4j</artifactId>
<version>1.6.1</version>
</dependency>
<!--或许你还需要这个包-->
<dependency>
<groupId>jaxen</groupId>
<artifactId>jaxen</artifactId>
<version>1.2.0</version>
</dependency>
- 创建一个类读取xml文档
首先需要通过流来读取XML文档,这是第一步。
InputStream inputStream = Thread.currentThread()
.getContextClassLoader()
.getResourceAsStream("user.xml");
- 读取XML文档取得XML对象
//获取指定的xml文档的DOM4J树
SAXReader reader = new SAXReader();
//获取XML文档对象
Document document = reader.read(inputStream);
- 获取根元素
//获取根元素
Element rootElement = document.getRootElement();
- 其余操作
//获取根元素下所有元素
List<Element> elements = rootElement.elements();
//或者返回一个<Element>迭代器
Iterator<Element> iterator = rootElement.elementIterator();
//遍历
for (Element element : elements){
/* System.out.println("elements:-->" +element);*/
System.out.println(element.getText());
}
//获取指定名称的所有的子元素
List<Element> list = rootElement.selectNodes("user");
for (Element e : list) {
System.out.println(e);
//获取此元素的所有属性
List<?> elementAttributes = e.attributes();
//获取此元素的指定属性
Attribute attribute = e.attribute("id");
//获取属性名
String name = attribute.getName();
//获取属性值
String value = attribute.getValue();
System.out.println(value);
//获取元素的 文本 值
String text = e.getStringValue();
}
创建XML文档
请按照以下顺序创建一个新的XML文档。
1.创建一个新的文档文件
首先我们需要先创建一个文档工厂,使用文档工厂创建文档对象。
//1. 使用 对象创建XML文档
DocumentFactory documentFactory = new DocumentFactory();
Document document = documentFactory.createDocument();
//或
Document document1 = DocumentHelper.createDocument();
2.添加元素
对新建文档的具体添加操作与对已有文档的具体添加操作相同。
对文档对象添加元素,达到为XML文件添加元素的目的。
//为根元素添加注释
document.addComment("用户根");
//为XML文档创建根元素
Element rootElement = document.addElement("User");
//为根元素添加一个子元素
Element childNode = rootElement.addElement("user");
//为子元素添加属性
childNode.addAttribute("id", "001");
//为子元素添加一个 name 子元素
Element nameElement = childNode.addElement("name");
//为元素添加内容
nameElement.setText("张三");
//为子元素添加一个 age 子元素
Element ageElement = childNode.addElement("age");
//为元素添加内容
ageElement.setText("20");
//为子元素添加一个 sex 子元素
Element sexElement = childNode.addElement("sex");
//为元素添加内容
sexElement.setText("false");
3.向XML文档写入所有元素
最终将文档对象写入到指定目录下。
//添加换行,生成格式(使其拥有易于阅读的格式)
OutputFormat format = OutputFormat.createPrettyPrint();
//在项目中创建一个xml文档
Writer writer = new FileWriter("D:\\源码\\untitled1\\src\\main\\resources\\User_1.xml");
//创建一个XML写入流,指定写入的文件
XMLWriter xmlWriter = new XMLWriter(writer,format);
//将根节点内包含的所有元素写入
xmlWriter.write(document);
xmlWriter.flush();
xmlWriter.close();
最终结果
添加
添加的具体操作和创建文档时具体操作相同。
有时候我们需要在已经存在内容的XML文档中添加元素,请使用以下方法。
首先我们需要先获取需要进行添加的XML文档的根元素。
InputStream inputStream = Thread.currentThread().getContextClassLoader()
.getResourceAsStream("user.xml");
//获取指定的xml文档的DOM4J树
SAXReader reader = new SAXReader();
//获取XML文档对象
Document document = reader.read(inputStream);
//获取根元素
Element rootElement = document.getRootElement();
添加元素应是对根元素内的某个位置添加一个新的元素,默认为添加到最后一个元素的下方。
InputStream inputStream= Thread.currentThread().getContextClassLoader()
.getResourceAsStream("User_1.xml");
//获取指定的xml文档的DOM4J树
SAXReader reader = new SAXReader();
//获取XML文档对象,此时读取到的文档对象内包含文档内原有的元素
Document document = reader.read(inputStream);
//获取根元素
Element rootElement = document.getRootElement();
//为根元素添加一个子元素
Element childNode = rootElement.addElement("user");
//为子元素添加属性
childNode.addAttribute("id", "002");
//为子元素添加一个 name 子元素
Element nameElement = childNode.addElement("name");
//为元素添加内容
nameElement.setText("王五");
//为子元素添加一个 age 子元素
Element ageElement = childNode.addElement("age");
//为元素添加内容
ageElement.setText("62");
//为子元素添加一个 sex 子元素
Element sexElement = childNode.addElement("sex");
//为元素添加内容
sexElement.setText("false");
//添加换行,生成格式
OutputFormat format = OutputFormat.createPrettyPrint();
//指定文件
Writer writer = new FileWriter("D:\\源码\\untitled1\\src\\main\\resources\\User_1.xml");
//创建一个XML写入流,指定写入的文件
XMLWriter xmlWriter = new XMLWriter(writer,format);
//将根节点内包含的所有元素写入
xmlWriter.write(document);
xmlWriter.flush();
xmlWriter.close();
添加元素到指定的位置
添加元素到指定的位置其实针对的是有内容的集合。
/*-----------------------------------以下为固定部分-----------------------------------------------*/
InputStream inputStream= Thread.currentThread().getContextClassLoader()
.getResourceAsStream("User_1.xml");
//获取指定的xml文档的DOM4J树
SAXReader reader = new SAXReader();
//获取XML文档对象
Document document = reader.read(inputStream);
//获取根元素
Element rootElement = document.getRootElement();
/*-----------------------------------以下为向指定位置添加-----------------------------------------------*/
//获取根元素中的某个名称的所有元素
List<Element> elementList = rootElement.elements("user");
/*以下为一个创建完整的元素的过程*/
//新建一个元素
Element newElement = DocumentHelper.createElement("user");
//为元素添加属性
newElement.addAttribute("id", "003");
//为元素添加一个 name 子元素
Element nameElement = newElement.addElement("name");
//为元素添加内容
nameElement.setText("赵柳");
//为元素添加一个 age 子元素
Element ageElement = newElement.addElement("age");
//为元素添加内容
ageElement.setText("45");
//为元素添加一个 sex 子元素
Element sexElement = newElement.addElement("sex");
//为元素添加内容
sexElement.setText("true");
//重点 向指定位置添加元素
elementList.add(2,newElement);
/*-----------------------------------以下为固定部分-----------------------------------------------*/
//添加换行,生成格式
OutputFormat format = OutputFormat.createPrettyPrint();
//指定文件
Writer writer = new FileWriter("D:\\源码\\untitled1\\src\\main\\resources\\User_1.xml");
//创建一个XML写入流,指定写入的文件
XMLWriter xmlWriter = new XMLWriter(writer,format);
//将根节点内包含的所有元素写入
xmlWriter.write(document);
xmlWriter.flush();
xmlWriter.close();
与创建文件时添加的不同之处
-
操作的对象不同
在创建文件时,需要使用new DocumentFactory();
或DocumentHelper.createDocument();
来创建一个新的文档对象,针对新文档对象进行添加,此时添加的元素还未写入XML文档文件。 -
添加时不同
在对已有内容的文档进行添加时,Element rootElement = document.getRootElement();
此对象已然包含有原始文档中的内容,是一个包含元素的rootElement对象。在添加时DOM4J应该会进行根节点内容检查,否则应是添加到内容的头部而不是尾部。
因此,在向指定位置添加时,拥有元素的rootElement对象尤为重要。添加时是添加的新的已经有了新的元素的rootElement对象,而不只是新的元素自己。 -
写入时不同
在创建新文档时,new FileWriter(“.....”)
是如果没有此文件则创建此文件。而在添加时则是执行的写入到此文件的操作。
与创建文件时添加的相同之处
- 添加的具体方式相同
都是使用获取的文档对象取得根元素针对根元素,使用相同的方法添加元素。添加元素的具体方法相同。
删除
如果你仔细阅读了上一节:向指定位置添加元素 ,那么我相信你已经猜到了如何修改与删除元素。
通过获取根元素中的某个名称的元素们,得到这种标签名的元素,通过判断删除元素与修改元素。
/*-----------------------------------以下为固定部分-----------------------------------------------*/
InputStream inputStream= Thread.currentThread().getContextClassLoader()
.getResourceAsStream("User_1.xml");
//获取指定的xml文档的DOM4J树
SAXReader reader = new SAXReader();
//获取XML文档对象
Document document = reader.read(inputStream);
//获取根元素
Element rootElement = document.getRootElement();
/*-----------------------------------以下为修改-----------------------------------------------*/
//获取根元素中的某个名称的所有元素
ListIterator<Element> elementList = rootElement.elements("user").listIterator();
while (elementList.hasNext()){
Element element = elementList.next();
Attribute attribute = element.attribute("id");
if (attribute.getValue().equals("001")){
elementList.remove();
break;
}
}
/*-----------------------------------以下为固定部分-----------------------------------------------*/
//添加换行,生成格式
OutputFormat format = OutputFormat.createPrettyPrint();
//在项目中创建一个xml文档
Writer writer = new FileWriter("D:\\源码\\untitled1\\src\\main\\resources\\User_1.xml");
//创建一个XML写入流,指定写入的文件
XMLWriter xmlWriter = new XMLWriter(writer,format);
//将根节点内包含的所有元素写入
xmlWriter.write(document);
xmlWriter.flush();
xmlWriter.close();
修改
修改与删除原理相同,都是针对集合操作。
/*-----------------------------------以下为固定部分-----------------------------------------------*/
InputStream inputStream= Thread.currentThread().getContextClassLoader()
.getResourceAsStream("User_1.xml");
//获取指定的xml文档的DOM4J树
SAXReader reader = new SAXReader();
//获取XML文档对象
Document document = reader.read(inputStream);
//获取根元素
Element rootElement = document.getRootElement();
/*-----------------------------------以下为修改-----------------------------------------------*/
//获取根元素中的某个名称的所有元素
ListIterator<Element> elementList = rootElement.elements("user").listIterator();
while (elementList.hasNext()){
Element element = elementList.next();
Attribute attribute = element.attribute("id");
if (attribute.getValue().equals("002")){
attribute.setValue("999");
break;
}
}
/*-----------------------------------以下为固定部分-----------------------------------------------*/
//添加换行,生成格式
OutputFormat format = OutputFormat.createPrettyPrint();
//在项目中创建一个xml文档
Writer writer = new FileWriter("D:\\源码\\untitled1\\src\\main\\resources\\User_1.xml");
//创建一个XML写入流,指定写入的文件
XMLWriter xmlWriter = new XMLWriter(writer,format);
//将根节点内包含的所有元素写入
xmlWriter.write(document);
xmlWriter.flush();
xmlWriter.close();