记录生活中的点点滴滴

0%

xml

可扩展标记语言 (Extensible Markup Language, XML) ,用于标记电子文件使其具有结构性的标记语言,可以用来标记数据、定义数据类型,是一种允许用户对自己的标记语言进行定义的源语言。 XML使用DTD(document type definition)文档类型定义来组织数据;格式统一,跨平台和语言,早已成为业界公认的标准。

XML基础

xml简介

什么是 XML?

  • XML 指可扩展标记语言(EXtensible Markup Language)
  • XML 是一种标记语言,很类似 HTML
  • XML 的设计宗旨是传输数据,而非显示数据
  • XML 标签没有被预定义。您需要自行定义标签
  • XML 被设计为具有自我描述性
  • XML 是 W3C 的推荐标准

xml语法

  • 所有 XML 元素都须有关闭标签

  • XML 标签对大小写敏感

  • XML 必须正确地嵌套

  • XML 文档必须有根元素

  • XML 的属性值须加引号

  • 实体引用

    如果你把字符 “<” 放在 XML 元素中,会发生错误,这是因为解析器会把它当作新元素的开始。

    1
    <message>if salary < 1000 then</message>

    为了避免这个错误,请用实体引用来代替 “<” 字符:

    1
    <message>if salary &lt; 1000 then</message>
  • 在 XML 中,空格会被保留

  • XML 以 LF 存储换行

    • 在 Windows 应用程序中,换行通常以一对字符来存储:回车符 (CR) 和换行符 (LF)。
    • 在 Unix 应用程序中,新行以 LF 字符存储。
    • 而 Macintosh 应用程序使用 CR 来存储新行。

xml验证

拥有正确语法的 XML 被称为“形式良好”的 XML。

通过 DTD 验证的 XML 是“合法”的 XML。

合法的 XML 文档是“形式良好”的 XML 文档,同样遵守文档类型定义 (DTD) 的语法规则:

1
2
3
4
5
6
7
8
<?xml version="1.0" encoding="ISO-8859-1"?>
<!DOCTYPE note SYSTEM "Note.dtd">
<note>
<to>George</to>
<from>John</from>
<heading>Reminder</heading>
<body>Don't forget the meeting!</body>
</note>

在上例中,DOCTYPE 声明是对外部 DTD 文件的引用。下面的段落展示了这个文件的内容。

命名冲突

在 XML 中,元素名称是由开发者定义的,当两个不同的文档使用相同的元素名时,就会发生命名冲突。

我们可以使用前缀来避免命名冲突:

1
2
3
4
5
6
<h:table>
<h:tr>
<h:td>Apples</h:td>
<h:td>Bananas</h:td>
</h:tr>
</h:table>
1
2
3
4
5
<f:table>
<f:name>African Coffee Table</f:name>
<f:width>80</f:width>
<f:length>120</f:length>
</f:table>

现在,命名冲突不存在了,这是由于两个文档都使用了不同的名称来命名它们的

元素 (< h:table > 和 < f:table >)。

通过使用前缀,我们创建了两种不同类型的

元素。

我们还可以使用命名空间(Namespaces)来解决命名冲突:

这个 XML 文档携带着某个表格中的信息:

1
2
3
4
5
6
<h:table xmlns:h="http://www.w3.org/TR/html4/">
<h:tr>
<h:td>Apples</h:td>
<h:td>Bananas</h:td>
</h:tr>
</h:table>

此 XML 文档携带着有关一件家具的信息:

1
2
3
4
5
<f:table xmlns:f="http://www.w3school.com.cn/furniture">
<f:name>African Coffee Table</f:name>
<f:width>80</f:width>
<f:length>120</f:length>
</f:table>

与仅仅使用前缀不同,我们为

标签添加了一个 xmlns 属性,这样就为前缀赋予了一个与某个命名空间相关联的限定名称。

XML 命名空间属性被放置于元素的开始标签之中,并使用以下的语法:

1
xmlns:namespace-prefix="namespaceURI"

注释:用于标示命名空间的地址不会被解析器用于查找信息。其惟一的作用是赋予命名空间一个惟一的名称。不过,很多公司常常会作为指针来使用命名空间指向实际存在的网页,这个网页包含关于命名空间的信息。

XML CDATA

所有 XML 文档中的文本均会被解析器解析。

只有 CDATA 区段(CDATA section)中的文本会被解析器忽略。

某些文本,比如 JavaScript 代码,包含大量 “<” 或 “&” 字符。为了避免错误,可以将脚本代码定义为 CDATA。

CDATA 部分中的所有内容都会被解析器忽略。

CDATA 部分由 ““ 结束:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
<script>
<![CDATA[
function matchwo(a,b)
{
if (a < b && a < 0) then
{
return 1;
}
else
{
return 0;
}
}
]]>
</script>

在上面的例子中,解析器会忽略 CDATA 部分中的所有内容。

Java解析xml

XML是一种通用的数据交换格式,它的平台无关性、语言无关性、系统无关性、给数据集成与交互带来了极大的方便。XML在不同的语言环境中解析方式都是一样的,只不过实现的语法不同而已。

XML的解析方式分为四种:1、DOM解析;2、SAX解析;3、JDOM解析;4、DOM4J解析。其中前两种属于基础方法,是官方提供的平台无关的解析方式;后两种属于扩展方法,它们是在基础的方法上扩展出来的,只适用于java平台。

针对以下XML文件,会对四种方式进行详细描述:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
<?xml version="1.0" encoding="UTF-8" ?>
<bookstore>
<book id="1">
<name>冰与火之歌</name>
<author>乔治马丁</author>
<year>2014</year>
<price>89</price>
</book>
<book id="2"><name>安徒生童话</name>
<year>2004</year>
<price>77</price>
<language>English</language>
</book>
</bookstore>

DOM解析

DOM的全称是Document Object Model,也即文档对象模型。在应用程序中,基于DOM的XML分析器将一个XML文档转换成一个对象模型的集合(通常称DOM树),应用程序正是通过对这个对象模型的操作,来实现对XML文档数据的操作。通过DOM接口,应用程序可以在任何时候访问XML文档中的任何一部分数据,因此,这种利用DOM接口的机制也被称作随机访问机制。

  DOM接口提供了一种通过分层对象模型来访问XML文档信息的方式,这些分层对象模型依据XML的文档结构形成了一棵节点树。无论XML文档中所描述的是什么类型的信息,即便是制表数据、项目列表或一个文档,利用DOM所生成的模型都是节点树的形式。也就是说,DOM强制使用树模型来访问XML文档中的信息。由于XML本质上就是一种分层结构,所以这种描述方法是相当有效的。

  DOM树所提供的随机访问方式给应用程序的开发带来了很大的灵活性,它可以任意地控制整个XML文档中的内容。然而,由于DOM分析器把整个XML文档转化成DOM树放在了内存中,因此,当文档比较大或者结构比较复杂时,对内存的需求就比较高。而且,对于结构复杂的树的遍历也是一项耗时的操作。所以,DOM分析器对机器性能的要求比较高,实现效率不十分理想。不过,由于DOM分析器所采用的树结构的思想与XML文档的结构相吻合,同时鉴于随机访问所带来的方便,因此,DOM分析器还是有很广泛的使用价值的。

    优点:

      1、形成了树结构,有助于更好的理解、掌握,且代码容易编写。

      2、解析过程中,树结构保存在内存中,方便修改。

    缺点:

      1、由于文件是一次性读取,所以对内存的耗费比较大。

      2、如果XML文件比较大,容易影响解析性能且可能会造成内存溢出。

  以下是解析代码:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
public class DomTest {
public static void main(String[] args) {
//创建一个DocumentBuilderFactory的对象
DocumentBuilderFactory dbf = DocumentBuilderFactory.newInstance();
try {
//创建DocumentBuilder对象
DocumentBuilder db = dbf.newDocumentBuilder();
//通过DocumentBuilder对象的parser方法加载books.xml文件到当前项目下
Document document = db.parse("test.xml");
//获取所有book节点的集合
NodeList bookList = document.getElementsByTagName("book");
//通过nodelist的getLength()方法可以获取bookList的长度
System.out.println("书本的个数:"+bookList.getLength());
//遍历每个book节点
for (int i = 0; i < bookList.getLength(); i++) {
System.out.println("开始遍历第"+(i+1)+"个书:");
//通过 item(i)方法 获取一个book节点,nodelist的索引值从0开始
Node book = bookList.item(i);
//获取book节点的所有属性集合
NamedNodeMap attributes = book.getAttributes();
System.out.println("第"+(i+1)+"个书有"+attributes.getLength()+"个属性");
//遍历book的属性
for (int j = 0; j < attributes.getLength(); j++) {
Node item = attributes.item(j);
//获取属性名
String nodeName = item.getNodeName();
//获取属性值
String nodeValue = item.getNodeValue();
System.out.println("属性名:"+nodeName+" 属性值:"+nodeValue);
}
//解析book节点的子节点
NodeList childNodes = book.getChildNodes();
//遍历childNodes获取每个节点的节点名和节点值
for (int j = 0; j < childNodes.getLength(); j++) {
//区分出text类型的node以及element类型的node
if(childNodes.item(j).getNodeType()==Node.ELEMENT_NODE){
//获取了element类型节点的节点名和节点值
System.out.println("属性名:"+childNodes.item(j).getNodeName());
System.out.println("属性值:"+childNodes.item(j).getFirstChild().getNodeValue());
}
}
}

} catch (ParserConfigurationException e) {
e.printStackTrace();
} catch (SAXException e) {
e.printStackTrace();
} catch (IOException e) {
e.printStackTrace();
}
}
}

输出结果:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
书本的个数:2
开始遍历第1个书:
第1个书有1个属性
属性名:id 属性值:1
属性名:name
属性值:冰与火之歌
属性名:author
属性值:乔治马丁
属性名:year
属性值:2014
属性名:price
属性值:89
开始遍历第2个书:
第2个书有1个属性
属性名:id 属性值:2
属性名:name
属性值:安徒生童话
属性名:year
属性值:2004
属性名:price
属性值:77
属性名:language
属性值:English

SAX解析

SAX的全称是Simple APIs for XML,也即XML简单应用程序接口。与DOM不同,SAX提供的访问模式是一种顺序模式,这是一种快速读写XML数据的方式。当使用SAX分析器对XML文档进行分析时,会触发一系列事件,并激活相应的事件处理函数,应用程序通过这些事件处理函数实现对XML文档的访问,因而SAX接口也被称作事件驱动接口。

    优点:

      1、采用事件驱动模式,对内存耗费比较小。

      2、适用于只处理XML文件中的数据时。

    缺点:

      1、编码比较麻烦。

      2、很难同时访问XML文件中的多处不同数据。

太特么长了,以后要是用了直接去搜吧,懒得写了

JDOM解析

特征:

      1、仅使用具体类,而不使用接口。

      2、API大量使用了Collections类。

同上,懒得写!

DOM4J解析

特征:

      1、JDOM的一种智能分支,它合并了许多超出基本XML文档表示的功能。

      2、它使用接口和抽象基本类方法。

      3、具有性能优异、灵活性好、功能强大和极端易用的特点。

      4、是一个开放源码的文件

  以下是解析代码:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
public class Dom4JTest {
public static void main(String[] args) {
// 创建SAXReader的对象reader
SAXReader saxReader = new SAXReader();
try {
// 通过reader对象的read方法加载books.xml文件,获取docuemnt对象。
Document document = saxReader.read(new File("test.xml"));
// 通过document对象获取根节点bookstore
Element root = document.getRootElement();
// 通过element对象的elementIterator方法获取迭代器
Iterator<Element> iterator = root.elementIterator();
// 遍历迭代器,获取根节点中的信息(书籍)
while (iterator.hasNext()){
System.out.println("开始遍历一本书....");
Element book = iterator.next();
// 获取book的属性名以及 属性值
List<Attribute> attributes = book.attributes();
for (Attribute attribute : attributes) {
System.out.println("属性名:"+attribute.getName()+" 属性值:"+attribute.getValue());
}
// 获取book的所有节点
Iterator<Element> it = book.elementIterator();
//遍历节点,获取节点名与节点值
while (it.hasNext()){
Element next = it.next();
System.out.println("节点名:"+next.getName()+" 节点值:"+next.getStringValue());
}
}
} catch (DocumentException e) {
e.printStackTrace();
}
}
}

输出结果:

1
2
3
4
5
6
7
8
9
10
11
12
开始遍历一本书....
属性名:id 属性值:1
节点名:name 节点值:冰与火之歌
节点名:author 节点值:乔治马丁
节点名:year 节点值:2014
节点名:price 节点值:89
开始遍历一本书....
属性名:id 属性值:2
节点名:name 节点值:安徒生童话
节点名:year 节点值:2004
节点名:price 节点值:77
节点名:language 节点值:English

比较总结

  DOM4J性能最好,连Sun的JAXM也在用DOM4J。目前许多开源项目中大量采用DOM4J,例如大名鼎鼎的Hibernate也用DOM4J来读取XML配置文件。如果不考虑可移植性,那就采用DOM4J。

JDOM和DOM在性能测试时表现不佳,在测试10M文档时内存溢出。在小文档情况下还值得考虑使用DOM和JDOM。虽然JDOM的开发者已经说明他们期望在正式发行版前专注性能问题,但是从性能观点来看,它确实没有值得推荐之处。另外,DOM仍是一个非常好的选择。DOM实现广泛应用于多种编程语言。它还是许多其它与XML相关的标准的基础,因为它正式获得W3C推荐(与基于非标准的Java模型相对),所以在某些类型的项目中可能也需要它(如在JavaScript中使用DOM)。

SAX表现较好,这要依赖于它特定的解析方式-事件驱动。一个SAX检测即将到来的XML流,但并没有载入到内存(当然当XML流被读入时,会有部分文档暂时隐藏在内存中)。