工作中会经常与 XML 文件,以下的 XML 文档基础知识是否还记得?
本 Chat 你将会获得以下知识:
- XML 概述
- XML 语法
- XML 约束之 DTD 约束
- JAXP 进行 DOM 解析
- 开发步骤及 CRUD 案例
适合人群:
- 编程小白
- 有工作经验想了解 XML 文档人员、职场老手,想回顾基础知识人员
- XML (eXtensible Markup Language,可扩展标记语言)。XML 技术是 w3c 组织发布的,目前推荐遵循的是 W3C 组织于 2000 发布的 XML1.0 规范。2001 年 12 月 13 日,XML 1.1 作为一份工作草案被发布,并作为一项候选推荐发布于 2002 年 10 月 15 日。
- XML 的设计目标是描述数据并集中于数据的内容。(而 HTML 设计目标是显示数据并集中于数据外观)
- XML 专门为 WEB 应用而设计,标记可以自定义。
...
- XML 具有错误验证机制。
- XML 区分大小写。
- XML 标记的属性必须用“”或’’括起来。
1.2 XML 的由来
HTML(Hypertext Markup Language,超文本标记语言)。
- HTML 的设计目标是显示数据并集中于数据外观。
- 标记是预定义的。
...
- HTML 是松散的,它允许错误的存在。这就是为什么现在我们用不同的浏览器浏览同一个网站时表现效果会有差异。
- HTML 不区分大小写。
- HTML 标记的属性可用也可不用""括起来。优点:使用简单,适合 Web 传输。缺点:语法不严谨,标记不可扩展,结构松散!
XML 集合 HTML 的优点并消除其缺点。既能利用标准通用标记语言的长处,又保留 html 的简单性。
1.3 XML 的主要用途- 数据描述,作为软件配置文件
- 存储数据,作为小型的数据库
- 大多数 XML 文档以 XML 声明作为开始,它向解析器提供了关于文档的基本信息。建议使用 XML 声明,但不是必需的。如果有的话,那么它一定是文档的第一行内容。
- 声明最多可以包含三个名称-值对。
- version:表示使用的 XML 版本:1.0,1.1
- encoding :表示该文档所使用的字符集。该声明中引用的ISO-8859-1 字符集包括大多数西欧语言用到的所有字符。如没有指定 encoding,XML 解析器会假定字符在 UTF-8 字符集中,这是一个几乎支持世界上所有语言的字符和象形文字的 Unicode 标准。
- standalone: 值可以是 yes 或 no。定义了是否可以在不读取任何其它文件的情况下处理该文档。
- 如果 XML 文档没有引用任何其它文件,则可以指定 standalone="yes"。
- 如果 XML 文档引用其它描述该文档可以包含什么的文件,则可以指定 standalone=“no”。缺省值为 standalone="no"
- XML 注释的格式:
注意事项:
- 注释可以出现在文档的任何位置,除了在 XML 声明之前;
- 注释不能在结束部分以外包含双连字符(- -);
- 注释内的任何标记都被忽略;
- 注释不能嵌套,如:
……-->
2.3 标签、元素、属性
标记: 左尖括号()之间文本,分为开始标签(如:)和结束标签()。
元素: 是指开始标签、结束标签以及位于二者之间的所有内容。 属性: 一个元素开始标签中的名称-值对。
//这是开始标记 Mrs. Eric //这是一个元素 Xu TianHeTangXia GuangZhou // state="gz" 这是元素属性 510100 //这是结束标记
注意事项:
- 标记必须遵循以下命名规则:
区分大小写,例如,和
是两个不同的标签。不能以数字或"_" (下划线)开头。不能以 xml(或 XML、或 Xml 等)开头。不能包含空格。名称中间不能包含冒号(:)。
- 果一个元素根本不包含标记之间的内容,称为空元素。例如:
,
。在空元素中,可以把结束斜杠放在开始标记中。例如:下面的两个换行元素和两个图像元素对于 XML 解析器来说是一回事:
![]()
- 良好的 XML 文档中,根元素必须唯一。其他元素都是这个根元素的子孙元素。例如:
Hello,world! 以下非法,存在两个根元素Hello,world!你好!
- 元素之间必须正确嵌套。一个元素中也可以嵌套若干子元素。但所有元素必须合理的嵌套,绝对不允许交叉嵌套的情况出现。例如
正确示例: I love XML
错误示例 I love
- 对于 XML 标签中出现的所有空格和换行,XML 解析程序都会当作标签内容进行处理。例如:下面两段内容的意义是不一样的
第一段:www.guilin.cn第二段: www.guilin.cn
由于在 XML 中,空格和换行都作为原始内容被处理,所以,在编写 XML 文件时,使用换行和缩进等方式来让原文件中的内容清晰可读的“良好”书写习惯可能要被迫改变。
- 属性必须有用引号括起的值。例如
正确示例...
错误示例...
XML 文档中的属性有两个规则1. 属性必须有值2. 值必须用引号括起,可以使用单引号,或使用双引号,但要始终保持一致
2.4 处理指令
- 处理指令,简称 PI (processing instruction)。处理指令用来指挥解析引擎如何解析 XML 文档内容。
- 一条处理指令包含一个目标,后跟数据。
- 例如,在 XML 文档中可以使用 xml-stylesheet 指令,通知 XML 解析引擎,应用 css 文件显示 xml 文档内容。
- 处理指令必须以“”作为结尾, XML 声明语句就是最常见的一种处理指令。例子:
文件清单:person.xml
张三 男 1380000000 zhangsan@163.com 88888888
文件清单:person.css
*{ font-size:30px; color:red; }
效果:
张三 男 1380000000 zhangsan@163.com 88888888
2.4 转义字符
对于一些单个字符,若想显示其原始样式,也可以使用转义的形式予以处理。
特殊字符替代符号&\&"\"'\' 2.5 CDATA在编写 XML 文件时,有些内容可能不想让解析引擎解析执行,而是当作原始内容处理。
遇到此种情况,可以把这些内容放在 CDATA 区里,对于 CDATA 区域内的内容,XML 解析程序不会处理,而是直接原封不动的输出。语法: ]]>
两个重要的问题
什么是良好的 XML?答:符合 W3C 制定的语法规范(也就是上面所提到的所有 XML 语法),我们就说这个 XML 是良好的 XML。
什么是有效的 XML?答:通过了用户自定义的 DTD 或者 Schema 校验的约束规则,我们就说这个 XML 是有效的 XML。
文档类型定义(Document Type Definition,简称 DTD)。
- DTD 定义了 XML 文档内容的结构,保证 XML 以一致的格式存储数据。
- XML 允许用户为应用程序创建自己的 DTD。
- 通过 DTD 定义的词汇表以及文档语法,XML 解析器可以检查 XML 文档内容的有效性。
文件清单:student.xml
张三 男 25 李四 女 20
文件清单:student.dtd
3.3 如何引用 DTD 约束
DTD 约束即可以作为一个单独的文件编写,也可以在 XML 文件内编写。
文件内部编写
]> 梅超风 女 40 ...
外部引用
XML 文件使用 DOCTYPE 声明语句来指明它所遵循的 DTD 文件,DOCTYPE 声明语句有两种形式:当引用的文件在本地时,采用如下方式: 例如: 。在 xml 文件中手写一下。当引用的文件是一个公共的文件时,采用如下方式: 例如:
3.4 DTD 语法
3.4.1 约束元素
元素格式
在 DTD 文档中使用 ELEMENT 声明一个 XML 元素,语法格式如下所示:
元素不能包含任何数据,但可以有属性(前提是必须声明其属性)。
- 不能有子元素。
- 不能有文本数据(包括空白)。
DTD 定义:
有效的 XML 内容: 或者 (推荐使用)-------------------------------------------------------无效的 XML 内容: (有空格!) 张三 (有文本!) 郭靖 (有子元素!)
PCDATA(只有 PCDATA 的元素)
PCDATA,指会被解析器解析的文本,通常指字符串内容。不包含任何类型的子元素内容。
ANY(带有任何内容的元素)元素可以包含任何类型的数据。
- 子元素(必须在 DTD 中有定义)
- 文本数据(包括空白)
DTD 定义:
有效的 XML 内容: 整个宇宙是无穷大的 银河系一号----------------------------------------------------------无效的 XML 内容: 银河系一号
ELEMENT(带有子元素(序列)的元素)
带有子元素的元素。而子元素出现的顺序和数目是可以指定的。参考下表:
项目书写语法描述顺序出现
子元素 a、b 必须同时出现,且 a 必须在 b 之前出现选择出现
子元素 a、b 只能有一个出现,要么是 a,要么是 b只出现一次
子元素 a 只能且必须出现一次一次或多次
子元素 a 要么出现一次,要么出现多次零次或多次
子元素 a 可以出现任意次(包括不出现,即出现零次)零次或一次
子元素 a 可以出现一次或不出现
DTD 文件的定义:-------------------------------------------------------有效的 XML 文档内容: 订单 1 号 订单 2 号 订单 3 号 订单 4 号 2014 年 4 月 10 日
3.4.1 约束属性
属性格式
XML 文档中的标签属性需通过 ATTLIST 为其设置属性语法格式:
设置说明
#REQUIRED
REQUIRED:必须设置该属性。DTD 文件的定义:-----------------------------------------------------------有效的 XML 文档内容: 郭靖------------------------------------------------------------无效的 XML 文档内容: 郭靖
#IMPLIED
IMPLIED:可以设置也可以不设置。DTD 文件的定义:---------------------------------------------------------------有效的 XML 文档内容: 郭靖--------------------------------------------------------------- 郭靖
#FIXED
FIXED:说明该属性的取值固定为一个值,在 XML 文件中不能为该属性设置其它值。但需要为该属性提供这个值 。DTD 文件的定义:------------------------------------------------------------有效的 XML 文档内容: 黄蓉 洪七公--------------------------------------------------------------无效的 XML 文档内容: 黄蓉 洪七公
直接使用默认值直接使用默认值:在 XML 中可以设置该值也可以不设置该属性值。若没设置则使用默认值。
DTD 文件的定义:-----------------------------------------------------------有效的 XML 文档内容: 岳不群 洪七公
属性值类型
CDATACDATA:表示属性值为普通文本字符串。CDATA 是不会被解析器解析的文本。在这些文本中的标签不会被当作标记来对待,其中的实体也不会被展开。
ENUMERATED属性的类型可以是一组取值的列表,在 XML 文件中设置的属性值只能是这个列表中的某个值(枚举)。注意,关键字 ENUMERATED 是不出现在 DTD 定义中的。
DTD 定义的内容:------------------------------------------------------------------有效的 XML 文档内容: -----------------------------------------------------------------无效的 XML 文档内容: //羊肉 没在枚举值出现的值是非法的!
ID表示属性的设置值为一个唯一值。属性的值只能由字母,下划线开始,不能出现空白字符。
DTD 定义的内容:--------------------------------------------------------------有效的 XML 文档内容: 张三 zhang@it315.org 李四 li@it315.org -------------------------------------------------------------无效的 XML 文档内容: 张三 zhang@it315.org //这里的”编号“值不能重复出现,必须唯一! 李四 li@it315.org
4 XML 解析方式概述
4.1 DOM(文档对象模式)
DOM(全称叫 Document Object Model)基于树或基于对象的 XML 处理模式。 XML 文档具有一个称为节点的信息单元层次结构; DOM 是描述那些节点和节点间关系的方式。 DOM 是万维网联盟(W3C)维护处理 XML 的标准。 DOM 是平台无关语言无关的。
DOM 处理原理:
- SAX 采用事件处理的方式解析 XML 文件,利用 SAX 解析 XML 文档,涉及两个部分:解析器和事件处理器:
- 解析器可以使用 JAXP 的 API 创建,创建出 SAX 解析器后,就可以指定解析器去解析某个 XML 文档。
- 解析器采用 SAX 方式在解析某个 XML 文档时,它只要解析到 XML 文档的一个组成部分,都会去调用事件处理器的一个方法,解析器在调用事件处理器的方法时,会把当前解析到的 xml 文件内容作为方法的参数传递给事件处理器。
- 事件处理器由程序员编写,程序员通过事件处理器中方法的参数,就可以很轻松地得到 sax 解析器解析到的数据,从而可以决定如何对数据进行处理。
SAX 处理原理:
优点: 这种处理的优点非常类似于流媒体的优点。分析能够立即开始,而不是等待所有的数据被处理。而且,由于应用程序只是在读取数据时检查数据,因此不需 要将数据存储在内存中。这对于大型文档来说是个巨大的优点。事实上,应用程序甚至不必解析整个文档;它可以在某个条件得到满足时停止解析。一般来说,SAX 还比它的替代者 DOM 快许多。
缺点: 由于应用程序没有以任何方式存储数据,使用 SAX 来更改数据或在数据流中往后移是不可能的。
基于 DOM(树)的处理的优点和缺点
优点: 1)由于树在内存中是持久的,因此可以修改它以便应用程序能对数据和结构作出更改。 2)它可以在任何时候在树中上下导航,而不是像 SAX 那样是一次性的处理。 3)DOM 使用起来也要简单得多。
缺点: 1)在内存中构造这样的树涉及大量的开销。大型文件完全占用系统内存容量的情况并不鲜见。 2)创建一棵 DOM 树可能是一个缓慢的过程。
4.4 常用的 XML 解析器1)JAXP2)DOM4J3)JDOM
5 JAXP 进行 DOM 解析
5.1 JAXP 概述
JAXP 开发包是 J2SE 的一部分,它由 javax.xml、org.w3c.dom 、org.xml.sax 包及其子包组成 在 javax.xml.parsers 包中,定义了几个工厂类,程序员调用这些工厂类,可以得到对 xml 文档进行解析的 DOM 或 SAX 的解析器对象。
5.2 核心 API 解读DocumentBuilderFactory: 是一个抽象工厂类,它不能直接实例化,但该类提供了一个newInstance
方法 ,这个方法会根据本地平台默认安装的解析器,自动创建一个工厂的对象并返回。调用工厂对象的 newDocumentBuilder
方法得到 DOM 解析器对象(DocumentBuilder)。
DocumentBuilder: 用于从 XML 文档中获取 DOM 文档实例。调用 DocumentBuilder 的 parse() 方法解析 XML 文档,得到代表整个文档的 Document 对象,这样可以利用 DOM 特性对整个 XML 文档进行操作了。
Document:代表了一个 XML 文档的树模型。以后所有的对 XML 文档的操作,都与解析器无关,直接在这个 Document 对象上进行操作就可以了。
Node:DOM 解析器在解析 XML 文档时,会把文档中的所有元素,按照其出现的层次关系,解析成一个个 Node 对象(节点)。在 DOM 中,节点之间关系如下:
- 位于一个节点之上的节点是该节点的父节点(parent)
- 一个节点之下的节点是该节点的子节点(children)
- 同一层次,具有相同父节点的节点是兄弟节点(sibling)
- 一个节点的下一个层次的节点集合是节点后代(descendant)
- 父、祖父节点及所有位于节点上面的,都是节点的祖先(ancestor)
节点(Node)可以是元素节点(Element
)、属性节点(Attr
)、文本节点(Text
)、实体节点(Entity
)等等。Node 对象提供了一系列常量来代表结点的类型,当开发人员获得某个 Node 类型后,就可以把 Node 节点转换成相应的节点对象(Node 的子类对象),以便于调用其特有的方法。
Node 对象提供了相应的方法去获得它的父结点或子结点。编程人员通过这些方法就可以读取整个 XML 文档的内容、或添加、修改、删除 XML 文档的内容了。
Transformer:用于把代表 XML 文件的 Document 对象转换为某种格式后进行输出,例如把 xml 文件应用样式表后转成一个 html 文档。利用这个对象,当然也可以把 Document 对象又重新写入到一个 XML 文件中。Transformer 类通过transform
方法完成转换操作,该方法接收一个源和一个目的地。我们可以通过:javax.xml.transform.dom.DOMSource
类来关联要转换的 document 对象, 用 javax.xml.transform.stream.StreamResult
对象来表示数据的目的地。 Transformer 对象通过TransformerFactory
获得。
1、创建 DocumentBuilderFactory 工厂实例 2、通过 DocumentBuilderFactory 实例的方法创建 DocumentBuilder 实例 3、通过 DocumentBuilder 实例的方法解析 XML 文档,产生 XML 的 Document 对象 4、获得 XML 文档的对应节点或节点列表(Node 或 NodeList) 5、利用节点(Node)的方法进行 CRUD 操作 6、如果是更新(添加、更新、删除)操作时,还必须利用 Transformer 把 XML 文档内容从内存写入到磁盘中
5.4 CRUD 案例 郭靖 男 25 黄蓉 女 20
读取节点信息
读取节点名称
```java @Testpublic void testRead() throws ParserConfigurationException, SAXException, IOException{//1、创建 DocumentBuilderFactory 工厂实例DocumentBuilderFactory factory = DocumentBuilderFactory.newInstance();//2、通过 DocumentBuilderFactory 实例的方法创建 DocumentBuilder 实例DocumentBuilder builder = factory.newDocumentBuilder();//3、通过 DocumentBuilder 实例的方法解析 XML 文档,产生 XML 的 Document 对象Document doc = builder.parse("src/student.xml");//4、获得 XML 文档的根节点Node root = doc.getChildNodes().item(0);//5、遍历整个 XML 文档,打印出所有节点名称parseChildNode(root);}
//解析指定节点下的所有子节点信息private void parseChildNode(Node root) { //打印节点名称 System.out.println(root.getNodeName()); NodeList cList = root.getChildNodes(); for(int i=0;i读取文本节点内容
java//3、通过 DocumentBuilder 实例的方法解析 XML 文档,产生 XML 的 Document 对象Document doc = builder.parse("src/student.xml");//4、根据节点名称获得 XML 文档的指定节点Element name = (Element)doc.getElementsByTagName("姓名").item(1);//读取节点的文本内容System.out.println(name.getTextContent());
__添加节点信息__>添加元素
javaDocument doc = builder.parse("src/student.xml");
//创建元素节点Element newElement = doc.createElement("师傅");newElement.setTextContent("江南七怪");
//把新建立的元素节点绑定到指定节点上Element name = (Element)doc.getElementsByTagName("学生").item(0);name.appendChild(newElement);
//利用 Transformer 把内存中更新后的 DOM 树刷新到磁盘中TransformerFactory tFactory= TransformerFactory.newInstance();Transformer former = tFactory.newTransformer();former.transform(new DOMSource(doc), new StreamResult(new FileOutputStream("E:\work\student.xml")));
>添加属性
java//在指定节点上设置属性Element name = (Element)doc.getElementsByTagName("姓名").item(1);name.setAttribute("帮派", "丐帮");
//利用 Transformer 把内存中更新后的 DOM 树刷新到磁盘中TransformerFactory tFactory= TransformerFactory.newInstance();Transformer former = tFactory.newTransformer();former.transform(new DOMSource(doc), new StreamResult(new FileOutputStream("E:\work\student.xml")));
__修改节点信息__>修改元素文本内容
java//修改指定节点文本内容,如“年龄”Element name = (Element)doc.getElementsByTagName("年龄").item(0);name.setTextContent("30");
//利用 Transformer 把内存中更新后的 DOM 树刷新到磁盘中TransformerFactory tFactory= TransformerFactory.newInstance();Transformer former = tFactory.newTransformer();former.transform(new DOMSource(doc), new StreamResult(new FileOutputStream(""E:\work\student.xml")));
>修改属性内容
java//修改指定节点属性内容,如“学号”Element name = (Element)doc.getElementsByTagName("学生").item(1);name.setAttribute("学号", "003");
//利用 Transformer 把内存中更新后的 DOM 树刷新到磁盘中TransformerFactory tFactory= TransformerFactory.newInstance();Transformer former = tFactory.newTransformer();former.transform(new DOMSource(doc), new StreamResult(new FileOutputStream(""E:\work\student.xml")));
__删除节点信息__
java//找到需要删除的节点Element name = (Element)doc.getElementsByTagName("年龄").item(1);
//在要删除的节点元素的父节点上面删除//方式 1:Element student = (Element)doc.getElementsByTagName("学生").item(1);student.removeChild(name);
//方式 2:name.getParentNode().removeChild(name);
//利用 Transformer 把内存中更新后的 DOM 树刷新到磁盘中TransformerFactory tFactory= TransformerFactory.newInstance();Transformer former = tFactory.newTransformer();former.transform(new DOMSource(doc), new StreamResult(new FileOutputStream(""E:\work\student.xml")));```
阅读全文: http://gitbook.cn/gitchat/activity/5ebf8fe9c39d800beb7d2181
您还可以下载 CSDN 旗下精品原创内容社区 GitChat App ,阅读更多 GitChat 专享技术内容哦。