Day05 xml详解
day05总结
今日内容
- XML语法
- XML约束之DTD
- XML解析器介绍
- XML解析之JAXP( DOM、SAX )
- DOM4J
- Schema
一、XML语法
XML概述
1 什么是XML
XML全称为Extensible Markup Language, 意思是可扩展的标记语言,它是 SGML(标准通用标记语言)的一个子集。
XML语法上和HTML比较相似,但HTML中的元素是固定的,而XML的标签是可以由用户自定义的。
W3C在1998年2月发布1.0版本;
W3C在2004年2月发布1.1版本,但因为1.1版本不能向下兼容1.0版本,所以1.1没有人用。同时,在2004年2月W3C又发布了1.0版本的第三版。我们要学习的还是1.0版本!!!
2 W3C组织
W3C是万维网联盟(World Wide Web Consortium)英文的缩写,它成立于1994年10月,以开放论坛的方式来促进开发互通技术(包括规格、指南、软件和工具),开发网络的全部潜能。万维网联盟(W3C)从1994年成立以来,已发布了90多份Web技术规范,领导着Web技术向前发展。
W3C认为自身不是官方组织,因此将它正式发布的规范称为推荐(建议)标准,意思是进一步标准化的建议,但是由于组织自身的权威性往往成为事实上的标准。
3 XML的作用
- 程序的配置文件(这也是最后大家使用XML最常见的目的);
- 数据交换:不同语言之间用来交换数据;
- 小型数据库:用来当数据库存储数据。
4 XML与HTML比较
- HTML的元素都是固定的,而XML可以自定义元素;
- HTML用浏览器来解析执行, XML的解析器通常需要自己来写(因为元素是自定义的);
- HTML只能用来表示网页,而XML可以做的事情很多。
5 XML和properties(属性文件)比较
- 属性文件只能存储平面信息,而XML可以存储结构化信息;
- 解析属性文件只需要使用Properties类就可以了,而解析XML文档是很复杂的。
XML语法概述
- 元素!!!
- 文档声明!!!
1 XML文档展示
2 XML文档的组成部分
- XML文档声明;重要
- XML处理指令;看完了,就可以忘了!
- XML元素;最重要
- XML特殊字符和CDATA区;一看就会
- XML注释。不看都会
XML文档声明
1 什么是xml文档声明
可以把xml文档声明看成是xml文档说明。
最简单的xml文档声明:<?xml version="1.0"?>
注意,XML是区别大小写,这一点不同与HTML!
2 xml文档声明结构
- version属性:用于说明当前xml文档的版本,因为都是在用1.0,所以这个属性值大家都写1.0,version属性是必须的;
- encoding属性:用于说明当前xml文档使用的字符编码集,xml解析器会使用这个编码来解析xml文档。encoding属性是可选的,默认为UTF-8。注意,如果当前xml文档使用的字符编码集是gb2312,而encoding属性的值为UTF-8,那么一定会出错的;
- standalone属性:用于说明当前xml文档是否为独立文档,如果该属性值为yes,表示当前xml文档是独立的,如果为no表示当前xml文档不是独立的,即依赖外部的文件。默认是yes
- 没有xml文档声明的xml文档,不是格式良好的xml文档;
- xml文档声明必须从xml文档的1行1列开始。
XML元素
1 XML元素的格式1
- xml元素包含:开始标签、元素体(内容)、结束标签。例如:<hello>大家好</hello>
- 空元素:空元素只有开始标签,没有元素体和结束标签,但空元素一定要闭合。例如:<hello/>
2 XML元素的格式2
- xml元素可以包含子元素或文本数据。例如:<a><b>hello</b></a>,a元素的元素体内容是b元素,而b元素的元素体内容是文本数据hello。
- xml元素可以嵌套,但必须是合法嵌套。例如:<a><b>hello<a></b>就是错误的嵌套。
3 XML文档的根元素
格式良好的xml文档必须且仅有一个根元素!
student1.xml
<?xml version="1.0" encoding="utf-8" standalone="no"?> <students> <student number="1001"> <name>zhangSan</name> <age>23</age> <sex>male</sex> </student> <student number="1002"> <name>liSi</name> <age>32</age> <sex>female</sex> </student> </students> |
student2.xml
<?xml version="1.0" encoding="utf-8" standalone="no"?> <student number="1001"> <name>zhangSan</name> <age>23</age> <sex>male</sex> </student> <student number="1002"> <name>liSi</name> <age>32</age> <sex>female</sex> </student> |
student1.xml是格式良好的xml文档,只有一个根元素,即students元素。
student2.xml不是格式良好的xml文档,有两个根元素,即两个student根元素。
4 元素中的空白
xml元素的元素体可以包含文本数据和子元素。
a.xml
<a><b>hello</b></a> |
b.xml
<a> <b> hello </b> </a> |
a.xml中,<a>元素只有一个子元素,即<b>元素。<b>元素只有一个文本数据,即hello。
b.xml中,<a>元素中第一部分为换行缩进,第二部分为<b>元素,第三部分为换行。b元素的文本数据为换行、缩进、hello、换行、缩进。
其中换行和缩进都是空白,这些空白是为了增强xml文档的可读性。但xml解析器可能会因为空白出现错误的解读,这说明在将来编写解析xml程序时,一定要小心空白。
5 元素命名规范
xml元素名可以包含字母、数字以及一些其它可见字符,但必须遵循下面的一些规范:
- 区分大小写:<a>和<A>是两个元素;
- 不能以数字或下划线开头:<1a>、<_a>都是错误的;
- 不能以xml开头:<xml>、<Xml>、<XML>都是错误的;
- 不能包含空格;
- 名称中间不能包含冒号:带有冒号的元素名是有特殊含义的
元素属性
- 属性由属性名与属性值构成,中间用等号连接;
- 属性值必须使用引号括起来,单引或双引;
- 定义属性必须遵循与标签名相同的命名规范;
- 属性必须定义在元素的开始标签中;
- 一个元素中不能包含相同的属性名;
- 有时属性和子元素可以互换,例如:<a><b>hello</b></a>可以改为<a b="hello"></a>
注释
- 注释以<!--开头,以-->结束;
- 注释中不能包含-->;
- 注释不能以--->结束。
转义字符和CDATA区
因为在xml文档中有些字符是特殊的,不能使用它们作为文本数据。例如:不能使用"<"或">"等字符作为文本数据,所以需要使用转义字符来表示。
例如<a><a></a>,你可能会说,其中第二个<a>是a元素的文本内容,而不是一个元素的开始标签,但xml解析器是不会明白你的意思的。
把<a><a></a>修饰为<a><a></a>,这就OK了。
转义字符都是以"&"开头,以";"结束。这与后面我们学习的实体是相同的。
CDATA区(CDATA段)
当大量的转义字符出现在xml文档中时,会使xml文档的可读性大幅度降低。这时如果使用CDATA段就会好一些。
在CDATA段中出现的"<"、">"、"""、"'"、"&",都无需使用转义字符。这可以提高xml文档的可读性。
<a><![CDATA[<a>]]></a> |
在CDATA段中不能包含"]]>",即CDATA段的结束定界符。
处理指令
处理指令,简称PI(Processing instruction)。处理指令用来指挥解析器如何解析XML文档内容。
例如,在XML文档中可以使用xml-stylesheet指令,通知XML解析器,应用css文件显示xml文档内容。
<?xml-stylesheet type="text/css" href="a.css"?> |
处理指令以"<?"开头,以"?>"结束,这一点与xml文档声明相同。
二、XML约束
XML约束概述
一个XML文档一旦有了约束,那么这个XML文档就只能使用约束中创建的元素及属性。如果约束没有创建<a>元素,那么XML文档就不能使用<a>元素!!!
1 什么是xml约束
因为xml文档是可以自定义元素的,这会让使用xml文档的应用程序无法知道xml文档的真实结构。通常应用程序都会要求xml文件的结构是固定的,以满足自己的需求,这就说明,不同的应用程序要求自己的xml文档必须符合一定的要求。
例如,当使用xml文档作为某个Java swing应用程序的配置文件时,要求xml文档结构如下:
<frame title="test xml" layout="java.awt.BorderLayout"> <bgcolor> <red>200</red> <green>0</green> <blue>0</blue> </bgcolor> <size> <width>300</width> <heigth>200</heigth> </size> <content> <label> <text>hello xml</text> <label> </content> </frame> |
当某个学生管理系统程序需要使用xml文档作为数据库时,要求xml文档结构如下:
<?xml version="1.0" encoding="utf-8" standalone="no"?> <students> <student number="1001"> <name>zhangSan</name> <age>23</age> <sex>male</sex> </student> <student number="1002"> <name>liSi</name> <age>32</age> <sex>female</sex> </student> <student number="1003"> <name>wangWu</name> <age>55</age> <sex>male</sex> </student> </students> |
xml文档约束是用另一个文件来约束xml文档的结构,例如要求xml文档的根元素必须是<students>,在<students>元素下可以包含0~n个<student>元素,每个<student>元素必须有一个number属性,而且还要有三个子元素,分别为<name>、<age>、<sex>,这三个子元素的内容必须为文本内容,而不能是子元素。
2 XML文档约束的类型
xml文档约束有两种类型:dtd和schema
- dtd:dtd是平面式文档,dtd文件不是xml文档,通常扩展名为".dtd"。它是最早的xml约束;
- schema:schema本身也是xml文档,它比dtd要更加强大,通常扩展名为".xsd"。它是新的xml文档约束,用来替代dtd。
DTD是老的XML约束
Schema是新的,用Schema替换掉DTD
会读即可!
DTD
1 什么是DTD
DTD(Document Type Definition),文档类型定义,用来约束XML文档。例如要求xml文档的根元素必须是<students>,在<students>元素下可以包含0~n个<student>元素,每个<student>元素必须有一个number属性,而且还要有三个子元素,分别为<name>、<age>、<sex>,这三个子元素的内容必须为文本内容,而不能是子元素。
2 DTD展示
<!ELEMENT students (student+)> <!ELEMENT student (name,age,sex)> <!ELEMENT name (#PCDATA)> <!ELEMENT age (#PCDATA)> <!ELEMENT sex (#PCDATA)> |
解读上面DTD:
- students元素中可以包含1~n个student元素;
- student元素中必须包含name、age、sex元素,而且顺序也是固定的;
- name元素内容为文本,即字符串;
- age元素内容为文本;
- sex元素内容为文本。
3 在XML文档中指定本地DTD
<?xml version="1.0" encoding="utf-8" standalone="no" ?> <!DOCTYPE students SYSTEM "students.dtd"> <students> <student> <name>zhangSan</name> <age>23</age> <sex>male</sex> </student> </students> |
<!ELEMENT students (student+)> <!ELEMENT student (name, age, sex)> <!ELEMENT name (#PCDATA)> <!ELEMENT age (#PCDATA)> <!ELEMENT sex (#PCDATA)> |
其中<!DOCTYPE students SYSTEM "students.dtd">,表示指定dtd文件。
指定DTD的语法:<!DOCTYPE 根元素 SYSTEM "DTD文件路径">
- 指定DTD的语法,以"<!DOCTYPE"开头,以">"结束;
- students表示根元素;
- SYSTEM表示dtd文件在本地;
- "students.dtd"表示DTD文件路径。
4 在XML文档中指定内部DTD
<?xml version="1.0" encoding="utf-8" standalone="no" ?> <!DOCTYPE students [ <!ELEMENT students (student+)> <!ELEMENT student (name, age, sex)> <!ELEMENT name (#PCDATA)> <!ELEMENT age (#PCDATA)> <!ELEMENT sex (#PCDATA)> ]> <students> <student> <name>zhangSan</name> <age>23</age> <sex>male</sex> </student> </students> |
5 在XML文档中指定外部公共DTD
外部公共DTD是说,DTD由某个公司或权威组织发布,例如如下:
<!DOCTYPE 根元素 PUBLIC "DTD名称" "DTD网址">
当然你需要知道要使用的DTD的名称和网址。如果某个机构公布了DTD,那么一定也会公布DTD的名称和网址。
上面例子中的公共DTD是不存在的。
DTD定义元素
1 定义元素的语法
使用ELEMENT声明元素:<!ELEMENT 元素名 内容类型或内容>
例如:<!ELEMENT name (#PCDATA)>
表示name元素的内容为文本数据
2 元素类型
元素类型可以是ANY或EMPTY
<!ELEMENT stu ANY>:表示stu元素的内容可以是任意元素,也可以是文本数据,也可以是文本数据+子元素,反正就是任意。
<!ELEMENT stu EMPTY>:表示stu不能有任何内容,即空元素。例如:<stu/>。
3 元素内容
元素内容可以是文本数据,也可以是子元素
<!ELEMENT stu (#PCDATA)>表示stu元素内容为文本,例如:<stu>hello</stu>
<!ELEMENT stu (name)>表示stu元素内容为name子元素,例如<stu><name></name><stu>,但要注意,如果<name>元素没有声明,那么就会出错。
4 子元素出现次数
可以使用"?"、"*"、"+"来指定子元素的出现次数
<!ELEMENT stu (name?)>表示stu元素可以有0~1个name子元素,即name子元素可有可无。
<!ELEMENT stu(name*)>表示stu元素可以有0~n个name子元素;
<!ELEMENT stu(name+)>表示stu元素可以有1~n个name子元素。
5 多个子元素
<!ELEMENT stu (name,age,sex)>表示stu必须有三个子元素,分别是name、age、sex,并且子元素出现的顺序也要与声明的顺序一致。
6 枚举子元素
<!ELEMENT stu (name | age | sex)表示stu只有一个子元素,可以是name、age、sex中的任意一个。
7 复合声明1
<!ELEMENT stu (name | age | sex)?>表示stu元素可以有0~1个(name | age | sex),而(name | age | sex)表示name、age、sex其中的一个。
<stu></stu>
<stu><name/></stu>
<stu><age/></stu>
<stu><sex/></stu>
8 复合声明2
<!ELEMENT stu (name | age | sex)*>表示stu元素可以有0~n个(name | age | sex),而(name | age | sex)表示name、age、sex其中的一个。
<stu></stu>
<stu><name/><age/><age/></stu>
<stu><name/><age/><name/><sex/><sex/></stu>
9 复合声明3
<!ELEMENT stu (name | age | sex)+>表示stu元素可以有1~n个(name | age | sex),而(name | age | sex)表示name、age、sex其中的一个。
<stu><age/></stu>
<stu><name/><name/></stu>
<stu><name/><age/><age/></stu>
<stu><name/><age/><name/><sex/><sex/></stu>
10 练习
<!DOCTYPE 课件 [ <!ELEMENT 章节 (简介, (标题, (段落 | 图片 | 表格 | 说明)+)+)> <!ELEMENT 简介 (#PCDATA)> <!ELEMENT 标题 (#PCDATA)> <!ELEMENT 段落 (#PCDATA)> <!ELEMENT 图片 (#PCDATA)> <!ELEMENT 表格 (#PCDATA)> <!ELEMENT 说明 (#PCDATA)> <!ELEMENT 课件 (章节+)> ]> |
根据上面DTD写xml文档!!!
DTD属性定义
1 属性定义的格式
Attribute List
<!ATTLIST 元素名
属性名1 属性类型 设置说明
属性名2 属性类型 设置说明
...>
<!ATTLIST student number CDATA #REQUIRED>表示student元素的number为文本类型,这个属性是必须的。
最常见的属性类型:CDATA,表示文本类型;
最常见的设置说明1:#REQUIRED,表示属性是必须的。
最常见的设置说明2:#IMPLIED,表示属性是可选的。
2 属性类型
- CDATA:属性值为任意文本数据;
- Enumerated:属性值必须是枚举列表中的一个;
- ID:属性值必须是唯一的,并且属性值不能以数字开头;
3 CDATA属性类型
CDATA,即Character Data(字符数据)。表示属性的类型为字符类型!
<!ATTLIST student number CDATA #REQUIRED>表示student元素的number属性是字符数据类型,并且是必须属性。
<student number="czbk_1001">
4 Enumerated属性类型
Enumerated不是关键字,定义枚举类型的属性需要给出枚举列表。当属性值为枚举类型时,那么这个属性的取值必须是枚举列表中的一个值。
<!ATTLIST student sex (male | female) #IMPLIED> 表示student的sex属性取值必须是male或者是female。并且这个属性是可选的。
5 ID属性类型
一个元素最多只能有一个ID 属性,ID属性用来表示元素唯一性的唯一标识。ID属性就相当与元素的身份证号,必须是唯一标识!
如果把student元素的number属性设定为ID类型,那么每个student元素的number属性值必须是唯一的,并且ID类型的属性值不能以数字开头。
<!ATTLIST student number ID #REQUIRED> 表示student的number属性值是ID类型,这说明student元素的number属性值必须是唯一的,不能和其他student的number属性值相同。
<student number="czbk_1001"/>
<student number="czbk_1002"/>
注意:不能以数字开头。
如果<a>元素有一个ID属性a
如果<b>元素有一个ID属性b
<a a="abc"/>
<b b="abc"/>
上面也是错误的,因为ID属性的值是不可以相同的。
6 设置说明
- #REQUIRED:表示属性是必须的;
- #IMPLIED:表示属性是可选的,即这个属性可以不给出;
三、XML解析器介绍
操作XML文档概述
1 如何操作XML文档
XML文档也是数据的一种,对数据的操作也不外乎是"增删改查"。也被大家称之为"CRUD"。
- C:Create;
- R:Retrieve;
- U:Update;
- D:Delete
2 XML解析技术
XML解析方式分为两种:DOM(Document Object Model)和SAX(Simple API for XML)。这两种方式不是针对Java语言来解析XML的技术,而是跨语言的解析方式。例如DOM还在Javascript中存在!
DOM是W3C组织提供的解析XML文档的标准接口,而SAX是社区讨论的产物,是一种事实上的标准。
DOM和SAX只是定义了一些接口,以及某些接口的缺省实现,而这个缺省实现只是用空方法来实现接口。一个应用程序如果需要DOM或SAX来访问XML文档,还需要一个实现了DOM或SAX的解析器,也就是说这个解析器需要实现DOM或SAX中定义的接口。提供DOM或SAX中定义的功能。
解析原理
1 DOM解析原理
使用DOM要求解析器把整个XML文档装载到一个Document对象中。Document对象包含文档元素,即根元素,根元素包含N多个子元素…
一个XML文档解析后对应一个Document对象,这说明使用DOM解析XML文档方便使用,因为元素与元素之间还保存着结构关系。
优先:使用DOM,XML文档的结构在内存中依然清晰。元素与元素之间的关系保留了下来!
缺点:如果XML文档过大,那么把整个XML文档装载进内存,可能会出现内存溢出的现象!
2 设置Java最大内存
运行Java程序,指定初始内存大小,以及最大内存大小。
java -Xms20m -Xmx100m MyClass
3 SAX解析原理
DOM会一行一行的读取XML文档,最终会把XML文档所有数据存放到Document对象中。SAX也是一行一行的读取XML文档,但是当XML文档读取结束后,SAX不会保存任何数据,同时整个解析XML文档的工作也就结束了。
但是,SAX在读取一行XML文档数据后,就会给感兴趣的用户一个通知!例如当SAX读取到一个元素的开始时,会通知用户当前解析到一个元素的开始标签。而用户可以在整个解析的过程中完成自己的业务逻辑,当SAX解析结束,不会保存任何XML文档的数据。
优先:使用SAX,不会占用大量内存来保存XML文档数据,效率也高。
缺点:当解析到一个元素时,上一个元素的信息已经丢弃,也就是说没有保存元素与元素之间的结构关系,这也大大限制了SAX的使用范围。如果只是想查询XML文档中的数据,那么使用SAX是最佳选择!
解析器概述
1 什么是XML解析器
DOM、SAX都是一组解析XML文档的规范,其实就是接口,这说明需要有实现者能使用,而解析器就是对DOM、SAX的实现了。一般解析器都会实现DOM、SAX两个规范!
- Crimson(sun):JDK1.4之前,Java使用的解析器。性能效差,可以忘记它了!
- Aelfred2(dom4j):DOM4J默认解析器,当DOM4J找不到解析器时会使用他自己的解析器。
JAXP概述
1 什么是JAXP
JAXP是由Java提供的,用于隐藏底层解析器的实现。Java要求XML解析器去实现JAXP提供的接口,这样可以让用户使用解析器时不依赖特定的XML解析器。
JAXP本身不是解析器(不是Xerces),也不是解析方式(DOM或SAX),它只是让用户在使用DOM或SAX解析器时不依赖特点的解析器。
当用户使用JAXP提供的方式来解析XML文档时,用户无需编写与特定解析器相关的代码,而是由JAXP通过特定的方式去查找解析器,来解析XML文档。
2 JAXP对DOM的支持
DocumentBuilderFactory factory = DocumentBuilderFactory.newInstance(); DocumentBuilder builder = factory.newDocumentBuilder(); Document doc = builder.parse("src/students.xml"); |
在javax.xml.parsers包中,定义了DOM解析器工厂类DocumentBuilderFactory,用于产生DOM解析器。DocumentBuilderFactory是一个抽象类,它有一个静态方法newInstance(),可以返回一个本类的实例对象。其实该方法返回的是DocumentBuilderFactory类的子类的实例(即工厂实例对象)。那么这个子类又是哪个子类呢?其实这个子类是由XML解析器提供商提供的,不同的厂商提供的工厂类对抽象工厂的实现是不同的。然后由工厂实例创建解析器对象。
那么newInstance()这个方法又是如果找到解析器提供商的工厂类的呢?此方法使用下面有序的查找过程来确定要加载的DocumentBuilderFactory实现类:
一、使用javax.xml.parsers.DocumentBuilderFactory系统属性。如果设置了这个系统属性的值,那么newInstance()方法就以这个属性的值来构造这个工厂的实例。通过下面的方法可以设置这个系统属性值。
System.setProperty("javax.xml.parsers.DocumentBuilderFactory", "工厂实现类名字");
我们不建议大家用上面的方法来硬编码这个系统属性的值,如果这样设置,假如将来需要更换解析器,就必需修改代码。
二、如果你没有设置上面的系统属性,newInstance()方法就会采用下面的途径来查找抽象工厂的实现类。第二个途径在查找JRE下的lib子目录下的jaxp.properties文件。如果这个文件存在,那么就读取这个文件。我们可以在%JAVA_HOME%\jre\lib\目录下创建一个jaxp.properties文件。在这个文件中给出一个键值对。如下所示:
javax.xml.parsers.DocumentBuilderFactory=工厂实现类名字
这个key名字必须是javax.xml.parsers.DocumentBuilderFactory,而相对应的值也必须设置类路径。
三、如果通过前两种途径下没有找到工厂的实现类,那么就需要使用服务API。这个服务API实际上是查找一个JAR文件的META-INF\ services\ javax.xml.parsers.DocumentBuilderFactory这个文件(该文件无扩展名)。如果找到了这个文件,就以这个文件的内容做为工厂实现类。这种方式被大多数解析器提供商所采用。在它们发布的解析器JAR包中往往会找到上述文件。然后在这个文件当中指定自己解析器的工厂类的名字。我们只需要把这个JAR文件的路径写到类路径(classpath)中就可以了。但要注意的是,如果在你的classpath中有多个解析器的JAR包路径,这时以前面的类路径优先。
四、如果说在前三种途径中都没有找到工厂实现类,那么就使用平台缺省工厂实现类。
在JAXP的早期的版本(5.0以前)中,除了JAXP API外,还包含了一个叫做Crimson的解析器。从JAXP1.2开始,Sun公司对Apache的Xerces解析器重新包装了一下,并将org.apache.xerces包名改为了com.sun.org.apache.xerces.internal,然后在JAXP的开发包中一起提供,作为缺省的解析器。我们所使用的JDK1.5中包含的缺省解析器就是被重新包装过后的Xerces解析器。
在获取到某个特定解析器厂商的DocumentBuilderFactory后,那么这个工厂对象创建出来的解析器对象当然就是自己厂商的解析器对象了。
3 JAXP对SAX的支持
SAXParserFactory factory = SAXParserFactory.newInstance(); SAXParser parser = factory.newSAXParser(); parser.parse("src/students.xml", new DefaultHandler() { public System.out.println("解析开始"); } public System.out.println("解析结束"); }
public throws SAXException { System.out.println("处理指令"); } public Attributes atts) throws SAXException { System.out.println("元素开始:" + qName); }
public throws SAXException { System.out.println("文本内容:" + new String(ch, start, length).trim()); }
public throws SAXException { System.out.println("元素结束:" + qName); } }); |
JAXP对SAX的支持与JAXP对DOM的支持是相同的,这里就不在赘述!
JDOM和DOM4J
1 JDOM和DOM4J概述
JDOM和DOM4J都是针对Java解析XML设计的方式,它们与DOM相似。但DOM不是只针对Java,DOM是跨语言的,DOM在Javascript中也可以使用。而JDOM和DOM4J都是专业为Java而设计的,使用JDOM和DOM4J,对Java程序员而言会更加方便。
2 JDOM和DOM4J比较
JDOM与DOM4J相比,DOM4J完胜!!!所以,我们应该在今后的开发中,把DOM4J视为首选。
在2000年,JDOM开发过程中,因为团队建议不同,分离出一支队伍,开发了DOM4J。DOM4J要比JDOM更加全面。
3 DOM4J查找解析器的过程
DOM4J首先会去通过JAXP的查找方法去查找解析器,如果找到解析器,那么就使用之;否则会使用自己的默认解析器Aelfred2。
DOM4J对DOM和SAX都提供了支持,可以把DOM解析后的Document对象转换成DOM4J的Document对象,当然了可以把DOM4J的Document对象转换成DOM的Document对象。
DOM4J使用SAX解析器把XML文档加载到内存,生成DOM对象。当然也支持事件驱动的方式来解析XML文档。
XML解析之JAXP(DOM)
JAXP获取解析器
1 JAXP相关包
JAXP相关开发包:javax.xml
DOM相关开发包:org.w3c.dom
SAX相关开发包:org.xml.sax
2 JAXP与DOM、SAX解析器的关系
JAXP只是作用只是为了让使用者不依赖某一特定DOM、SAX的解析器实现,当使用JAXP API时,使用者直接接触的就是JAXP API,而不用接触DOM、SAX的解析器实现API。
3 JAXP获取DOM解析器
当我们需要解析XML文档时,首先需要通过JAXP API解析XML文档,获取Document对象。然后用户就需要使用DOM API来操作Document对象了。
DocumentBuilderFactory factory = DocumentBuilderFactory.newInstance(); factory.setValidating(false); DocumentBuilder builder = factory.newDocumentBuilder(); Document doc = builder.parse("src/students.xml"); |
4 JAXP保存Document
当我们希望把Document保存到文件中去时,可以使用Transformer对象的transform()方法来完成。想获取Transformer对象,需要使用TransformerFactory对象。
与JAXP获取DOM解析器一样,隐藏了底层解析器的实现。也是通过抽象工厂来完成的,这里就不在赘述了。
TransformerFactory tFactory = TransformerFactory.newInstance(); Transformer transformer = tFactory.newTransformer(); trans.setOutputProperty(OutputKeys.ENCODING, "UTF-8"); trans.setOutputProperty(OutputKeys.DOCTYPE_SYSTEM, "students.dtd"); trans.setOutputProperty(OutputKeys.INDENT, "yes"); Source source = new DOMSource(doc); Result result = new StreamResult(xmlName); transformer.transform(source, result); |
Transformer类的transform()方法的两个参数类型为:Source和Result,DOMSource是Source的实现类,StreamResult是Result的实现类。
5 JAXP创建Document
有时我们需要创建一个Document对象,而不是从XML文档解析而来。这需要使用DocumentBuider对象的newDocument()方法。
DocumentBuilderFactory factory = DocumentBuilderFactory .newInstance(); DocumentBuilder builder = factory.newDocumentBuilder(); Document doc = builder.newDocument(); doc.setXmlVersion("1.0"); doc.setXmlStandalone(true); |
5 学习DOM之前,先写两个方法
- Document getDocument(String xmlName):通过xmlName获取Document对象;
- void saveDocument(Document doc, String xmlName):保存doc到xmlName文件中。
DOM API概述
1 Document对应XML文档
无论使用什么DOM解析器,最终用户都需要获取到Document对象,一个Document对象对应整个XML文档。也可以这样说,Document对象就是XML文档在内存中的表示形式。
通常我们最为"关心"的就是文档的根元素。所以我们必须要把Document获取根元素的方法记住:Element getDocumentElement()。然后通过根元素再一步步获取XML文档中的数据。
2 DOM API中的类
在DOM中提供了很多接口,用来描述XML文档中的组成部分。其中包括:文档(Document)、元素(Element)、属性(Attr)、文本(Text)、注释(Comment)、CDATA段(CDATASection)等等。无论是哪种XML文档组成部分,都是节点(Node)的子接口。
3 Node方法介绍
Node基本方法:
- String getNodeName():获取当前节点的名字。如果当前节点是Element,那么返回元素名称。如果当前节点是Text那么返回#text。如果当前节点是Document那么返回#document;
- String getNodeValue():获取当前节点的值。只有文本节点有值,其它节点的值都为null;
- String getTextContext():获取当前节点的文本字符串。如果当前节点为Text,那么获取节点内容。如果当前节点为Element,那么获取元素中所有Text子节点的内容。例如当前节点为:<name>zhangSan</name>,那么本方法返回zhangSan。如果当前节点为:<student><name>zhangSan</name><age>23</age><sex>male</sex></student>,那么本方法返回zhangSan23male。
- short getNodeType():获取当前节点的类型。Node中有很多short类型的常量,可以通过与这些常量的比较来判断当前节点的类型。if(node.getNodeType() == Node.ELEMENT_NODE);
Node获取子节点和父节点方法,只有Document和Element才能使用这些方法:
-
- int getLength():获取集合长度;
- Node item(int index):获取指定下标的节点。
- Node getFirstNode():获取当前节点的第一个子节点;
- Node getLastNode():获取当前节点的最后一个子节点;
- Node getParentNode():获取当前节点的父节点。注意Document的父节点为null。
Node获取弟兄节点的方法,只有Element才能使用这些方法:
- Node getNextSibling():获取当前节点的下一个兄弟节点;
- Node getPreviousSibling():获取当前节点的上一个兄弟节点。
Node添加、替换、删除子节点方法
:
- Node appendChild(Node newChild):把参数节点newChild添加到当前节点的子节点列表的末尾处。返回值为被添加的子节点newChild对象,方便使用链式操作。如果newChild在添加之前已经在文档中存在,那么就是修改节点的位置了;
- Node insertBefore(Node newChild, Node refNode):把参数节点newChild添加到当前节点的子节点refNode之前。返回值为被添加的子节点newChild对象,方便使用链式操作。如果refNode为null,那么本方法与appendNode()方法功能相同。如果newChild节点在添加之前已经在文档中存在,那么就是修改节点的位置了。
- Node removeNode(Node oldChild):从当前节点中移除子元素oldChild。返回值为被添加的子节点oldChild对象,方便使用链式操作。
- Node replaceNode(Node newChild, Node oldChild):将当前节点的子节点oldChild替换为newChild。
Node获取属性集合方法,只有Element可以使用:
- NamedNodeMap getAttributes():返回当前节点的属性集合。NamedNodeMap表示属性的集合,方法如下:
- int getLength():获取集合中属性的个数;
- Node item(int index):获取指定下标位置上的属性节点;
- Node getNamedItem(String name):获取指定名字的属性节点;
- Node removeNamedItem(String name):移除指定名字的属性节点,返回值为移除的属性节点;
- Node setNamedItem(Node arg):添加一个属性节点,返回值为添加的属性节点。
Node的判断方法:
- boolean hasChildNodes():判断当前节点是否有子节点;
- boolean hasAttribute():判断当前节点是否有属性。
4 Docment方法介绍
创建节点方法:
- Attr createAttribute(String name):创建属性节点;
- CDATASection createCDATASection(String data):创建CDATA段节点;
- Comment createComment(String data):创建注释;
- Element createElement(String tagName):创建元素节点;
- Text createTextNode(String data):创建文本节点;
获取子元素方法:
- Element getElementById(String elementId):通过元素的ID属性获取元素节点,如果没有DTD指定属性类型为ID,那么这个方法将返回null;
- Element getDocumentElement():获取文档元素,即获取根元素。
文档声明相关方法:
- String getXmlVersion():获取文档声明的version属性值;
- String getXmlEncoding():获取文档声明的encoding属性值;
- String getXmlStandalone():获取文档声明的standalone属性值;
- void setXmlVersion():设置文档声明version属性值;
- void setXmlStandalone():设置文档声明standalone属性值。
5 Element方法介绍
获取方法:
- NodeList getElementsByTagName(String tagName):获取当前元素的指定元素名称的所有子元素;
- String getTagName():获取当前元素的元素名。调用元素节点的getNodeName()也是返回名;
属性相关方法:
- String getAttribute(String name):获取当前元素指定属性名的属性值;
- Attr getAttributeNode(String name):获取当前元素指定属性名的属性节点;
- boolean hasAttribute(String name):判断当前元素是否有指定属性;
- void removeAttribute(String name):移除当前元素的指定属性;
- void removeAttributeNode(Attr attr):移除当前元素的指定属性;
- void setAttribute(String name, String value):为当前元素添加或修改属性;
- Attr setAttributeNode(Attr attr):为当前元素添加或修改属性,返回值为添加的属性;
6 Attr方法介绍
- String getName():获取当前属性节点的属性名;
- String getValue():获取当前属性节点的属性值;
- void setValue(String value):设置当前属性节点的属性值;
- boolean isId():判断当前属性节点是否为ID类型属性。
SAX
SAX概述
1 SAX解析原理
首先我们想一下,DOM解析器是不是需要把XML文档遍历一次,然后把每次读取到的数据转换成节点对象(到底哪一种节点对象,这要看解析时遇到了什么东西)保存起来,最后生成一个Document对象返回。也就是说,当你调用了builder.parse("a.xml")后,这个方法就会把XML文档中的数据转换成节点对象保存起来,然后生成一个Document对象。这个解析XML文档的过程在parse()方法调用结束后也就结束了。我们的工作是在解析之后,开始对Document对象进行操作。
但是SAX不同,当SAX解析器的parse()方法调用结束后,不会给我们一个Document对象,而是什么都不给。SAX不会把XML数据保存到内存中,如果我们的解析工作是在SAX解析器的parse()方法调用结束后开始,那么就已经晚了!!!这说明我们必须在SAX解析XML文档的同时完成我们的工作。
SAX解析器在解析XML文档的过程中,读取到XML文档的一个部分后,会调用ContentHandler(内部处理器)中的方法。例如当SAX解析到一个元素的开始标签时,它会调用ContentHandler的startElement()方法;在解析到一个元素的结束标签时会调用ContentHandler的endElement()方法。
ContentHandler是一个接口,我们的工作是编写该接口的实现类,然后创建实现类的对象,在SAX解析器开始解析之前,把我们写的内容处理类对象交给SAX解析器,这样在解析过程中,我们的内容处理中的方法就会被调用了。
2 获取SAX解析器
与DOM相同,你应该通过JAXP获取SAX解析器,而不是直接使用特定厂商的SAX解析器。JAXP查找特定厂商的SAX解析器实现的方式与查找DOM解析器实现的方式完全相同,这里就不在赘述了。
SAXParserFactory factory = SAXParserFactory.newInstance();
javax.xml.parsers.SAXParser parser = factory.newSAXParser();
parser.parse("src/students.xml", new MyContentHandler());
上面代码中,MyContentHandler就是我们自己需要编写的ContentHandler的实现类对象。
3 内容处理器
org.xml.sax.ContentHandler中的方法:
- void setDocumentLocator(Locator locator):与定位相关,例如获取行数、实体、标识等信息,我们可以忽略他的存在;
- void endDocument() throws SAXException:文档解析结束之后被调用;
- void startPrefixMapping(String prefix,String uri)throws SAXException:与名称空间相关,忽略;
- void endPrefixMapping(String prefix) throws SAXException:与名称空间相关,忽略;
- void startElement(String uri,String local,String qName,Attributes atts)throws SAXException:开始解析一个元素时被调用,其中uri、local这两个参数与名称空间相关,可以忽略。qName表示当前元素的名称,atts表示当前元素的属性集合;
- void endElement(String uri,String localName,String qName)throws SAXException:一个元素解析结束后会被调用;
- void characters(char[] ch,int start,int length)throws SAXException:解析到文本数据时会被调用,ch表示当前XML文档所有内容对应的字符数组,不只是当前文本元素的内容。start表示当前文本数据在整个XML文档中的开始下载位置,length是当前文本数据的长度;
- void ignorableWhitespace(char[] ch,int start,int length)throws SAXException:解析到空白文本数据时会被调用,可以忽略!
- void processingInstruction(String target,String data)throws SAXException:解析到处理指令时会被调用,可以忽略!
- void skippedEntity(String name)throws SAXException:解析到实体时会被调用,可以忽略!
org.xml.sax.helpers.DefualtHandler对ContentHandler做了空实现,所以我们可以自定义内容处理器时可以继承DefaultHandler类。
SAX应用
测试SAX
public @Test public SAXParserFactory factory = SAXParserFactory.newInstance(); SAXParser parser = factory.newSAXParser(); parser.parse("src/students.xml", new MyContentHandler()); } private @Override public System.out.println("开始解析..."); } @Override public System.out.println("解析结束..."); } @Override public Attributes atts) throws SAXException { System.out.println(qName + "元素解析开始"); } @Override public throws SAXException { System.out.println(qName + "元素解析结束"); } @Override public throws SAXException { String s = new String(ch, start, length); if(s.trim().isEmpty()) { return; } System.out.println("文本内容:" + s); } @Override public throws SAXException { } @Override public throws SAXException { System.out.println("处理指令"); } } } |
2 使用SAX打印XML文档
public @Test public ParserConfigurationException, SAXException, IOException { SAXParserFactory factory = SAXParserFactory.newInstance(); SAXParser parser = factory.newSAXParser(); parser.parse("src/students.xml", new MyContentHandler()); } private @Override public System.out.println("<?xml version='1.0' encoding='utf-8'?>"); }
@Override public Attributes atts) throws SAXException { StringBuilder sb = new StringBuilder(); sb.append("<").append(qName); for(int i = 0; i < atts.getLength(); i++) { sb.append(" "); sb.append(atts.getQName(i)); sb.append("="); sb.append("'"); sb.append(atts.getValue(i)); sb.append("'"); } sb.append(">"); System.out.print(sb); }
@Override public throws SAXException { System.out.print("</" + qName + ">"); }
@Override public throws SAXException { System.out.print(new String(ch, start, length)); } } } |
DOM4J
DOM4J概述
1 DOM4J是什么
DOM4J是针对Java开发人员专门提供的XML文档解析规范,它不同与DOM,但与DOM相似。DOM4J针对Java开发人员而设计,所以对于Java开发人员来说,使用DOM4J要比使用DOM更加方便。
DOM4J对DOM和SAX提供了支持,使用DOM4J可以把org.dom4j.document转换成org.w3c.Document,DOM4J也支持基于SAX的事件驱动处理模式。
使用者需要注意,DOM4J解析的结果是org.dom4j.Document,而不是org.w3c.Document。DOM4J与DOM一样,只是一组规范(接口与抽象类组成),底层必须要有DOM4J解析器的实现来支持。
DOM4J使用JAXP来查找SAX解析器,然后把XML文档解析为org.dom4j.Document对象。它还支持使用org.w3c.Document来转换为org.dom4j.Docment对象。
2 DOM4J中的类结构
在DOM4J中,也有Node、Document、Element等接口,结构上与DOM中的接口比较相似。但还是有很多的区别:
在DOM4J中,所有XML组成部分都是一个Node,其中Branch表示可以包含子节点的节点,例如Document和Element都是可以有子节点的,它们都是Branch的子接口。
Attribute是属性节点,CharacterData是文本节点,文本节点有三个子接口,分别是CDATA、Text、Comment。
3 DOM4J获取Document对象
使用DOM4J来加载XML文档,需要先获取SAXReader对象,然后通过SAXReader对象的read()方法来加载XML文档:
SAXReader reader = new SAXReader(); // reader.setValidation(true); Document doc = reader.read("src/students.xml"); |
4 DOM4J保存Document对象
保存Document对象需要使用XMLWriter对象的write()方法来完成,在创建XMLWriter时还可以为其指定XML文档的格式(缩进字符串以及是否换行),这需要使用OutputFormat来指定。
doc.addDocType("students", "", "students.dtd"); OutputFormat format = new OutputFormat("\t", true); format.setEncoding("UTF-8"); XMLWriter writer = new XMLWriter(new FileWriter(xmlName), format); writer.write(doc); writer.close(); |
5 DOM4J创建Document对象
DocumentHelper类有很多的createXXX()方法,用来创建各种Node对象。
Document doc = DocumentHelper.createDocument(); |
Document操作 (*****)
1 遍历students.xml
涉及的相关方法:
- Element getRootElement():Document的方法,用来获取根元素;
- List elements():Element的方法,用来获取所有子元素;
- String attributeValue(String name):Element的方法,用来获取指定名字的属性值;
- Element element(String name):Element的方法,用来获取第一个指定名字的子元素;
- Element elementText(String name):Element的方法,用来获取第一个指定名字的子元素的文本内容。
分析步骤:
- 获取Document对象;
- 获取root元素;
- 获取root所有子元素
- 遍历每个student元素;
- 打印student元素number属性;
- 打印student元素的name子元素内容;
- 打印student元素的age子元素内容;
- 打印student元素的sex子元素内容。
2 给学生元素添加<score>子元素
涉及的相关方法:
- Element addElement(String name):Element的方法,为当前元素添加指定名字子元素。返回值为新建元素对象;
- setText(String text):Element的方法,为当前元素设置文本内容。
分析步骤:
- 获取Document对象;
- 获取root对象;
- 获取root所有子元素;
- 遍历所有学生子元素;
- 创建<score>元素,为<score>添加文本内容;
- 把<score>元素添加到学生元素中。
- 保存Document对象。
3 为张三添加friend属性,指定为李四学号
涉及方法:
- addAttribute(String name, String value):Element的方法,为当前元素添加属性。
分析步骤:
- 获取Document对象;
- 获取root对象;
- 获取root所有子元素;
- 创建两个Element引用:zhangSanEle、liSiEle,赋值为null;
- 遍历所有学生子元素;
- 如果zhangSanEle和liSiEle都不是null,break;
- 判断当前学生元素的name子元素文本内容是zhangSan,那么把当前学生元素赋给zhangSanEle;
- 判断当前学生元素的name子元素文本内容是liSi,那么把当前学生元素赋给liSiEle。
- 判断zhangSanEle和liSiEle都不为null时:
- 获取liSiEle的number属性。
- 为zhangSanEle添加friend属性,属性值为liSi的number属性值。
- 保存Document对象。
4 删除number为ID_1003的学生元素
涉及方法:
- boolean remove(Element e):Element和Document的方法,移除指定子元素;
- Element getParent():获取父元素,根元素的父元素为null。
分析步骤:
- 获取Document对象;
- 获取root对象;
- 获取root所有子元素;
- 遍历所有学生子元素;
- 判断当前学生元素的number属性是否为ID_1003;
- 获取当前元素的父元素;
- 父元素中删除当前元素;
- 保存Document对象.
5 通过List<Student>生成Document并保存
涉及方法:
- DocumentHelper.createDocument():创建Document对象;
- DocumentHelper.createElement(String name):创建指定名称的Element元素。
分析步骤:
- 创建Document对象;
- 为Document添加根元素<students>;
- 循环遍历学生集合List<Student>;
- 把当前学生对象转换成Element元素;
- 把Element元素添加到根元素中;
- 保存Document对象。
把学生转换成Element步骤分析:
- 创建Element对象;
- 为Element添加number属性,值为学生的number;
- 为Element添加name子元素,文本内容为学生的name;
- 为Element添加age子元素,文本内容为学生的age;
- 为Element添加sex子元素,文本内容为学生的sex。
6 新建赵六学生元素,插入到李四之前
涉及方法:
- int indexOf(Node node):Branch的方法,查找指定节点,在当前Branch的子节点集合中的下标位置。
分析步骤:
- 创建赵六学生对象;
- 通过学生对象创建赵六学生元素;
- 通过名称查找李四元素;
- 查看李四元素在其父元素中的位置;
- 获取学生子元素List;
- 将赵六元素插入到List中。
通过名字查找元素:
- 获取Document;
- 获取根元素;
- 获取所有学生元素;
- 遍历学生元素;
- 获取学生元素name子元素的文本内容,与指定名称比较;
- 返回当前学生元素。
7 其它方法介绍
Node方法:
- String asXML():把当前节点转换成字符串,如果当前Node是Document,那么就会把整个XML文档返回;
- String getName():获取当前节点名字;Document的名字就是绑定的XML文档的路径;Element的名字就是元素名称;Attribute的名字就是属性名;
- Document getDocument():返回当前节点所在的Document对象;
- short getNodeType():获取当前节点的类型;
- String getNodeTypeName():获取当前节点的类型名称,例如当前节点是Document的话,那么该方法返回Document;
- String getStringValue():获取当前节点的子孙节点中所有文本内容连接成的字符串;
- String getText():获取当前节点的文本内容。如果当前节点是Text等文本节点,那么本方法返回文本内容;例如当前节点是Element,那么当前节点的内容不是子元素,而是纯文本内容,那么返回文本内容,否则返回空字符串;
- void setDocument(Document doc):给当前节点设置文档元素;
- void setParent(Element parent):给当前节点设置父元素;
- void setText(String text):给当前节点设置文本内容;
Branch方法:
- void add(Element e):添加子元素;
- void add(Node node):添加子节点;
- void add(Comment comment):添加注释;
- Element addElement(String eleName):通过名字添加子元素,返回值为子元素对象;
- void clearContent():清空所有子内容;
- List content():获取所有子内容,与获取所有子元素的区别是,<name>liSi</name>元素没有子元素,但有子内容;
- Element elementById(String id):如果元素有名为"ID"的属性,那么可以使用这个方法来查找;
- int indexOf(Node node):查找子节点在子节点列表中的下标位置;
- Node node(int index):通过下标获取子节点;
- int nodeCount():获取子节点的个数;
- Iterator nodeIterator():获取子节点列表的迭代器对象;
- boolean remove(Node node):移除指定子节点;
- boolean remove(Commont commont):移除指定注释;
- boolean remove(Element e):移除指定子元素;
- void setContent(List content) :设置子节点内容;
Document方法:
- Element getRootElement():获取根元素;
- void setRootElement():设置根元素;
- String getXmlEncoding():获取XML文档的编码;
- void setXmlEncoding():设置XML文档的编码;
Element方法:
- void add(Attribute attr):添加属性节点;
- void add(CDATA cdata):添加CDATA段节点;
- void add(Text Text):添加Text节点;
- Element addAttribute(String name, String value):添加属性,返回值为当前元素本身;
- Element addCDATA(String cdata):添加CDATA段节点;
- Element addComment(String comment):添加属性节点;
- Element addText(String text):添加Text节点;
- void appendAttributes(Element e):把参数元素e的所有属性添加到当前元素中;
- Attribute attribute(int index):获取指定下标位置上的属性对象;
- Attribute attribute(String name):通过指定属性名称获取属性对象;
- int attributeCount():获取属性个数;
- Iterator attributeIterator():获取当前元素属性集合的迭代器;
- List attributes():获取当前元素的属性集合;
- String attributeValue(String name):获取当前元素指定名称的属性值;
- Element createCopy():clone当前元素对象,但不会copy父元素。也就是说新元素没有父元素,但有子元素;
- Element element(String name):获取当前元素第一个名称为name的子元素;
- Iterator elementIterator():获取当前元素的子元素集合的迭代器;
- Iterator elementIterator(String name):获取当前元素中指定名称的子元素集合的迭代器;
- List elements():获取当前元素子元素集合;
- List elements(String name):获取当前元素指定名称的子元素集合;
- String elementText(String name):获取当前元素指定名称的第一个元素文件内容;
- String elementTextTrime(String name):同上,只是去除了无用空白;
- boolean isTextOnly():当前元素是否为纯文本内容元素;
- boolean remove(Attribute attr):移除属性;
- boolean remove(CDATA cdata):移除CDATA;
- boolean remove(Text text):移除Text。
DocumentHelper静态方法介绍:
- static Document createDocument():创建Dcoument对象;
- static Element createElement(String name):创建指定名称的元素对象;
- static Attribute createAttrbute(Element owner, String name, String value):创建属性对象;
- static Text createText(String text):创建属性对象;
- static Document parseText(String text):通过给定的字符串生成Document对象;
Schema
Schema概述
我们学习Schema的第一目标是:参照Schema的要求可以编写XML文档;
第二目标是:可以自己来定义Schema文档。
1 Schema是什么
XML文档的约束,用来替代DTD。
DTD文档不是XML语法,而Schema本身也是XML文档,这对解析器来说不用再去处理非XML的文档了;
DTD只能表述平台线束,而Schema本身也是XML,所以可以描述结构化的约束信息。
DTD不只约束元素或属性的类型,但Schema可以。例如让age属性的取值在0~100之间。
Schema文档的扩展名为xsd,即XML Schema Definition。
为students.xml编写DTD
<!ELEMENT students (student+)> <!ELEMENT student (name,age,sex)> <!ELEMENT name (#PCDATA)> <!ELEMENT age (#PCDATA)> <!ELEMENT sex (#PCDATA)> <!ATTLIST student number CDATA #REQUIRED> |
3 为students.xml编写schema
<?xml <xsd:schema <xsd:element <xsd:complexType <xsd:sequence> <xsd:element </xsd:sequence> </xsd:complexType> <xsd:complexType <xsd:sequence> <xsd:element <xsd:element <xsd:simpleType> <xsd:restriction <xsd:maxInclusive <xsd:minInclusive </xsd:restriction> </xsd:simpleType> </xsd:element> <xsd:element <xsd:simpleType> <xsd:restriction <xsd:enumeration <xsd:enumeration </xsd:restriction> </xsd:simpleType> </xsd:element> </xsd:sequence> <xsd:attribute </xsd:complexType> </xsd:schema> |
参照Schema编写XML文档
我们参照上面的Schema文档编写一个studens.xml文件
<?xml version="1.0" encoding="utf-8" standalone="no" ?> |
名称空间相关内容
XSD文档中是创建元素和属性的地方;
XML文档中是使用元素和属性的地方。
所以在XML文档中需要说明使用了哪些XSD文档。
1 什么是名称空间
名称空间是用来处理XML元素或属性的名字冲突问题。你可以理解为Java中的包!包的作用就是用来处理类的名字冲突问题。
注意:XML与Java有很大区别,虽然都是处理名字冲突问题,但语法上是有很大区别的。例如在Java中可以使用import来导入类,但你一定要保存你导入的类已经在类路径(classpath)中存在。使用package为当前Java文件中所有类声明名。但XML的名称空间要比Java复杂很多。
我们在下面讲解XML名称空间时,会使用Java包的概念来理解XML的名称空间的概念,所以现在大家就要注意这么几个特性:
- import:导包,声明名称空间;
- package:定义包,指定目标名称空间;
- classpath:添加到类路径,关联XSD文件
2 声明名称空间(导包)
无论是在XML中,还是在XSD中,都需要声明名称空间。这与Java中使用import来导包是一个道理。当然,前提是有包(创建类是使用了package)才可以导,没包就不能导了。如果被定义的元素在声明时没有指定目标名称空间,那么就是在无名称空间中,那么我们在使用这些在无名称空间中的元素时,就不用再去声明名称空间了。
声明名称空间使用xmlns,例如:xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"。这表示声明了一个名称空间,相当与Java中的import。但是,Java中的import的含义是在下面使用的类,如果没有给出包名,那么就是import导入的这个类。而xmlns表示,下面使用xsi为前缀的元素或属性,都是来自http://www.w3.org/2001/XMLSchema-instance名称空间。也就是说给名称空间起了一个简称,这就相当于我们称呼"北京传智播客教育科技有限公司"为"传智"一样。"传智"就是简称。
例如在XSD文件中,xmlns:xsd="http://www.w3.org/2001/XMLSchema"就是声明名称空间,而这个名称空间是W3C的名称空间,无需关联文件就可以直接声明!在XSD文件中所有使用xsd为前面的元素和属性都是来自http://www.w3.org/2001/XMLSchema名称空间。
名称空间命名:一般名称空间都是以公司的URL来命名,即网址!当然也可以给名称空间命名为aa、bb之类的名字,但这可能会导致名称空间的重名问题。
前缀命名:前缀的命名没有什么要求,但一般对http://www.w3.org/2001/XMLSchema名称空间的前缀都是使用xs或xsd。http://www.w3.org/2001/XMLSchema-instance的前缀使用xsi。
在XML文档中声明xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"名称空间的目的是使用xsi中的一个属性:xsi:noNamespaceSchemaLocation,它是用W3C提供的库属性,用来关联XSD文件用的。当然,它只能关联那些没有"目标名称空间"的XSD文件。下面会讲解目标名称空间!
3 默认名称空间
所谓默认名称空间就是在声明名称空间时,不指定前缀,也可以理解为前缀为空字符串的意思。这样定义元素时,如果没有指定前缀的元素都是在使用默认名称空间中的元素。
当在文档中使用<xxx>时,那么<xxx>元素就是http://www.itcast.cn名称空间中声明的元素。
注意:没有指定前缀的属性不表示在默认名称空间中,而是表示没有名称空间。也就是说,默认名称空间不会涉及到属性,只对元素有效!
XPath(扩展)
XPath概述
1 什么是XPath
XPath即为XML路径语言(XML Path Language),它是一种用来确定XML文档中某部分位置的语言。XPath基于XML的树状结构,提供在数据结构树中找寻节点的能力。起初 XPath 的提出的初衷是将其作为一个通用的、介于XPointer与XSL间的语法模型。但是 XPath 很快的被开发者采用来当作小型查询语言。
2 DOM4J对XPath的支持
在DOM4J中,Node接口中的三个方法最为常用:
- List selectNodes(String xpathExpression):在当前节点中查找满足XPath表达式的所有子节点;
- Node selectSingleNode(String xpathExpression):在当前节点中查找满足XPath表达式的第一个子节点;
- String valueOf(String xpathExpression):在当前节点中查找满足XPath表达式的第一个子节点的文本内容;
自学笔记:
day05
昨天内容回顾
1、在末尾添加节点:
* 创建标签 createElement
* 创建文本 createTextNode
* 把文本添加到标签下面 appendChild
2、获取标签下面的子标签的唯一有效方法
* getElementsByTagName
3、nodeType
* 标签节点:1
* 属性节点:2
* 文本节点:3
* 父节点:parentNode
4、方法
* appendChild
* 在某个节点之前插入节点:insertBefore(new,old);
- 通过父节点插入
* 删除节点:removeChild方法
- 通过父节点删除
* 替换节点:replaceChild(new,old)
- - 通过父节点替换
5、innerHTML属性
* 获取文本内容
* 向标签内设置内容(可以是html代码)
** 写js的方法的命名
add1()、add_1()
** 不要写单一的单词 add()
** 不要把下划线放在开始位置 _add()
1、表单提交方式
* 使用submit提交
<form>
.....
<input type="submit" />
</form>
* 使用button提交表单
- 代码
//实现提交方法
function form1() {
//获取form
var form1 = document.getElementById("form1");
//设置action
form1.action = "hello.html";
//提交form表单
form1.submit();
}
* 使用超链接提交
- 代码
<a href="hello.html?username=123456">使用超链接提交</a>
* onclick:鼠标点击事件
onchange:改变内容(一般和select一起使用)
onfocus:得到焦点 (ie5、某些版本的ie6)
onblur:失去焦点
2、xml的简介(了解)
* eXtensible Markup Language:可扩展标记型语言
** 标记型语言:html是标记型语言
- 也是使用标签来操作
** 可扩展:
- html里面的标签是固定,每个标签都有特定的含义 <h1> <br/> <hr/>
- 标签可以自己定义,可以写中文的标签 <person></person>、<猫></猫>
* xml用途
** html是用于显示数据,xml也可以显示数据(不是主要功能)
** xml主要功能,为了存储数据
* xml是w3c组织发布的技术
* xml有两个版本 1.0 1.1
- 使用都是1.0版本,(1.1版本不能向下兼容)
3、xml的应用
* 不同的系统之间传输数据
** qq之间数据的传输
** 画图分析过程
* 用来表示生活中有关系的数据
* 经常用在文件配置
* 比如现在连接数据库 肯定知道数据库的用户名和密码,数据名称
* 如果修改数据库的信息,不需要修改源代码,只要修改配置文件就可以了
4、xml的语法
(1)xml的文档声明(***)
* 创建一个文件 后缀名是 .xml
* 如果写xml,第一步 必须要有 一个文档声明(写了文档声明之后,表示写的是xml文件的内容)
** <?xml version="1.0" encoding="gbk"?>
*** 文档声明必须写在 第一行第一列
* 属性
- version:xml的版本 1.0(使用) 1.1
- encoding:xml编码 gbk utf-8 iso8859-1(不包含中文)
- standalone:是否需要依赖其他文件 yes/no
* xml的中文乱码问题解决
** 画图分析乱码问题
** 保存时候的编码和设置打开时候的编码一致,不会出现乱码
(2)定义元素(标签)(***)
(3)定义属性(***)
(4)注释(***)
(5)特殊字符(***)
(6)CDATA区(了解)
(7)PI指令(了解)
5、xml的元素(标签)定义(*****)
** 标签定义
** 标签定义有开始必须要有结束:<person></person>
** 标签没有内容,可以在标签内结束 ; <aa/>
** 标签可以嵌套,必须要合理嵌套
*** 合理嵌套 <aa><bb></bb></aa>
*** 不合理嵌套 <aa><bb></aa></bb>: 这种方式是不正确的
** 一个xml中,只能有一个根标签,其他标签都是这个标签下面的标签
** 在xml中把空格和换行都当成内容来解析,
**** 下面这两段代码含义是不一样的
* <aa>1111111</aa>
* <aa>
11111111111
</aa>
** xml标签可以是中文
** xml中标签的名称规则
(1)xml代码区分大小写
<p> <P>:这两个标签是不一样的
(2)xml的标签不能以数字和下划线(_)开头
<2a> <_aa>: 这样是不正确的
(3)xml的标签不能以xml、XML、Xml等开头
<xmla> <XmlB> <XMLC>: 这些都是不正确的
(4)xml的标签不能包含空格和冒号
<a b> <b:c> : 这些是不正确的
6、xml中属性的定义(*****)
* html是标记型文档,可以有属性
* xml也是标记型文档,可以有属性
* <person id1="aaa" id2="bbb"></person>
** 属性定义的要求
(1)一个标签上可以有多个属性
<person id1="aaa" id2="bbb"></person>
(2)属性名称不能相同
<person id1="aaa" id1="bbb"></person>:这个是不正确,不能有两个id1
(3)属性名称和属性值之间使用= ,属性值使用引号包起来 (可以是单引号,也可以是双引号 )
(4)xml属性的名称规范和元素的名称规范一致
7、xml中的注释(*****)
* 写法 <!-- xml的注释 -->
** 注意的地方
**** 注释不能嵌套
<!-- <!-- --> -->
<!-- <!-- <sex>nv</sex>--> -->
** 注释也不能放到第一行,第一行第一列必须放文档声明
8、xml中的特殊字符(*****)
* 如果想要在xml中现在 a<b ,不能正常显示,因为把<当做标签
* 如果就想要显示,需要对特殊字符 < 进行转义
** < <
> >
9、CDATA区(了解)
* 可以解决多个字符都需要转义的操作 if(a<b && b<c && d>f) {}
* 把这些内容放到CDATA区里面,不需要转义了
** 写法
<![CDATA[ 内容 ]]>
- 代码
<![CDATA[ <b>if(a<b && b<c && d>f) {}</b> ]]>
** 把特殊字符,当做文本内容,而不是标签
10、PI指令(处理指令)(了解)
* 可以在xml中设置CSS样式
* 写法: <?xml-stylesheet type="text/css" href="css的路径"?>
* 设置样式,只能对英文标签名称起作用,对于中文的标签名称不起作用的。
** xml的语法的总结
所有 XML 元素都须有关闭标签
XML 标签对大小写敏感
XML 必须正确地嵌套顺序
XML 文档必须有根元素(只有一个)
XML 的属性值须加引号
特殊字符必须转义 --- CDATA
XML 中的空格、回车换行会解析时被保留
11、xml的约束(dtd)
* 为什么需要约束?
** 比如现在定义一个person的xml文件,只想要这个文件里面保存人的信息,比如name age等,但是如果在xml文件中
写了一个标签<猫>,发现可以正常显示,因为符合语法规范。但是猫肯定不是人的信息,xml的标签是自定义的,需要技术来
规定xml中只能出现的元素,这个时候需要约束。
* xml的约束的技术 : dtd约束 和 schema约束 (看懂)
12、dtd的快速入门
* 创建一个文件 后缀名 .dtd
步骤:
(1)看xml中有多少个元素 ,有几个元素,就在dtd文件中写几个 <!ELEMENT>
(2)判断元素是简单元素还是复杂元素
- 复杂元素:有子元素的元素
<!ELEMENT 元素名称 (子元素)>
- 简单元素:没有子元素
<!ELEMENT 元素名称 (#PCDATA)>
(3)需要在xml文件中引入dtd文件
<!DOCTYPE 根元素名称 SYSTEM "dtd文件的路径">
** 打开xml文件使用浏览器打开的,浏览器只负责校验xml的语法,不负责校验约束
** 如果想要校验xml的约束,需要使用工具(myeclipse工具)
** 打开myeclipse开发工具
*** 创建一个项目 day05
*** 在day05的src目录下面创建一个xml文件和一个dtd文件
*** 当xml中引入dtd文件之后,比如只能出现name age,多写了一个a,会提示出错
13、dtd的三种引入方式
(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 使用配置文件 使用 外部的dtd文件
- <!DOCTYPE struts PUBLIC "-//Apache Software Foundation//DTD Struts Configuration 2.0//EN"
"http://struts.apache.org/dtds/struts-2.0.dtd">
14、使用dtd定义元素
* 语法: <!ELEMENT 元素名 约束>
* 简单元素:没有子元素的元素
<!ELEMENT name (#PCDATA)>
*** (#PCDATA): 约束name是字符串类型
*** EMPTY : 元素为空(没有内容)
- <sex></sex>
*** ANY:任意
* 复杂元素:
<!ELEMENT person (name,age,sex,school)>
- 子元素只能出现一次
* <!ELEMENT 元素名称 (子元素)>
* 表示子元素出现的次数
+ : 表示一次或者多次,至少要出现一次
? :表示出现零次或者一次
* :表示出现零次或者多次
* 子元素之间使用逗号进行隔开 ,
** 表示元素出现的顺序
* 子元素之间使用|隔开
** 表示元素只能出现其中的任意一个
15、使用dtd定义属性
* 语法: <!ATTLIST 元素名称
属性名称 属性类型 属性的约束
>
* 属性类型
- CDATA: 字符串
- <!ATTLIST birthday
ID1 CDATA #REQUIRED
>
- 枚举 : 表示只能在一定的范围内出现值,但是只能每次出现其中的一个
** 红绿灯效果
** (aa|bb|cc)
- <!ATTLIST age
ID2 (AA|BB|CC) #REQUIRED
>
- ID: 值只能是字母或者下划线开头
- <!ATTLIST name
ID3 ID #REQUIRED
>
* 属性的约束
- #REQUIRED:属性必须存在
- #IMPLIED:属性可有可无
- #FIXED: 表示一个固定值 #FIXED "AAA"
- 属性的值必须是设置的这个固定值
- <!ATTLIST sex
ID4 CDATA #FIXED "ABC"
>
- 直接值
* 不写属性,使用直接值
* 写了属性,使用设置那个值
- <!ATTLIST school
ID5 CDATA "WWW"
>
16、实体的定义
* 语法: <!ENTITY 实体名称 "实体的值">
*** <!ENTITY TEST "HAHAHEHE">
*** 使用实体 &实体名称; 比如 &TEST;
** 注意
* 定义实体需要写在内部dtd里面,
如果写在外部的dtd里面,有某些浏览器下,内容得不到
17、xml的解析的简介(写到java代码)(***今天最重要的内容*****)
* xml是标记型文档
* js使用dom解析标记型文档?
- 根据html的层级结构,在内存中分配一个树形结构,把html的标签,属性和文本都封装成对象
- document对象、element对象、属性对象、文本对象、Node节点对象
* xml的解析方式(技术):dom 和 sax
** 画图分析使用dom和sax解析xml过程
*** dom解析和sax解析区别:
** dom方式解析
* 根据xml的层级结构在内存中分配一个树形结构,把xml的标签,属性和文本都封装成对象
* 缺点:如果文件过大,会造成内存溢出
* 优点:很方便实现增删改操作
** sax方式解析
* 采用事件驱动,边读边解析
- 从上到下,一行一行的解析,解析到某一个对象,返回该对象名称
* 缺点:不能实现增删改操作
* 优点:如果文件过大,不会造成内存溢出,方便实现查询操作
* 想要解析xml,首先需要解析器
** 不同的公司和组织提供了 针对dom和sax方式的解析器,通过api方式提供
*** sun公司提供了针对dom和sax解析器 jaxp
*** dom4j组织,针对dom和sax解析器 dom4j(*** 实际开发中****)
*** jdom组织,针对dom和sax解析器 jdom
18、jaxp的api的查看
** jaxp是javase的一部分
** jaxp解析器在jdk的javax.xml.parsers包里面
** 四个类:分别是针对dom和sax解析使用的类
*** dom:
DocumentBuilder : 解析器类
- 这个类是一个抽象类,不能new,
此类的实例可以从 DocumentBuilderFactory.newDocumentBuilder() 方法获取
- 一个方法,可以解析xml parse("xml路径") 返回是 Document 整个文档
- 返回的document是一个接口,父节点是Node,如果在document里面找不到想要的方法,到Node里面去找
- 在document里面方法
getElementsByTagName(String tagname)
-- 这个方法可以得到标签
-- 返回集合 NodeList
createElement(String tagName)
-- 创建标签
createTextNode(String data)
-- 创建文本
appendChild(Node newChild)
-- 把文本添加到标签下面
removeChild(Node oldChild)
-- 删除节点
getParentNode()
-- 获取父节点
NodeList list
- getLength() 得到集合的长度
- item(int index) 根据下标取到具体的值
for(int i=0;i<list.getLength();i++) {
list.item(i)
}
getTextContent()
- 得到标签里面的内容
DocumentBuilderFactory: 解析器工厂
- 这个类也是一个抽象类,不能new
newInstance() 获取 DocumentBuilderFactory 的实例。
*** sax:
SAXParser:解析器类
SAXParserFactory: 解析器工厂
19、使用jaxp实现查询操作
*** 查询xml中所有的name元素的值
* 步骤
//查询所有name元素的值
/*
* 1、创建解析器工厂
DocumentBuilderFactory.newInstance();
* 2、根据解析器工厂创建解析器
builderFactory.newDocumentBuilder();
* 3、解析xml返回document
* Document document = builder.parse("src/person.xml");
* 4、得到所有的name元素
使用document.getElementsByTagName("name");
* 5、返回集合,遍历集合,得到每一个name元素
- 遍历 getLength() item()
- 得到元素里面值 使用 getTextContent()
* */
*** 查询xml中第一个name元素的值
* 步骤
/*
* 1、创建解析器工厂
* 2、根据解析器工厂创建解析器
* 3、解析xml,返回document
*
* 4、得到所有name元素
* 5、使用返回集合,里面方法 item,下标获取具体的元素
NodeList.item(下标): 集合下标从0开始
* 6、得到具体的值,使用 getTextContent方法
*
* */
20、使用jaxp添加节点
*** 在第一个p1下面(末尾)添加 <sex>nv</sex>
**步骤
/*
* 1、创建解析器工厂
* 2、根据解析器工厂创建解析器
* 3、解析xml,返回document
*
* 4、得到第一个p1
* - 得到所有p1,使用item方法下标得到
* 5、创建sex标签 createElement
* 6、创建文本 createTextNode
* 7、把文本添加到sex下面 appendChild
* 8、把sex添加到第一个p1下面 appendChild
*
* 9、回写xml
* */
21、使用jaxp修改节点
*** 修改第一个p1下面的sex内容是nan
** 步骤
/*
* 1、创建解析器工厂
* 2、根据解析器工厂创建解析器
* 3、解析xml,返回document
*
* 4、得到sex item方法
* 5、修改sex里面的值
*** setTextContent方法
*
* 6、回写xml
* */
22、使用jaxp删除节点
*** 删除<sex>nan</sex>节点
** 步骤
/*
* 1、创建解析器工厂
* 2、根据解析器工厂创建解析器
* 3、解析xml,返回document
*
* 4、获取sex元素
* 5、获取sex的父节点 使用getParentNode方法
* 6、删除使用父节点删除 removeChild方法
*
* 7、回写xml
* */
23、使用jaxp遍历节点
** 把xml中的所有元素名称打印出来
** 步骤
/*
* 1、创建解析器工厂
* 2、根据解析器工厂创建解析器
* 3、解析xml,返回document
*
* ====使用递归实现=====
* 4、得到根节点
* 5、得到根节点子节点
* 6、得到根节点子节点的子节点
* */
** 遍历的方法
//递归遍历的方法
private static void list1(Node node) {
//判断是元素类型时候才打印
if(node.getNodeType() == Node.ELEMENT_NODE) {
System.out.println(node.getNodeName());
}
//得到一层子节点
NodeList list = node.getChildNodes();
//遍历list
for(int i=0;i<list.getLength();i++) {
//得到每一个节点
Node node1 = list.item(i);
//继续得到node1的子节点
//node1.getChildNodes()
list1(node1);
}
}
Day05 xml详解的更多相关文章
- Web.xml详解(转)
这篇文章主要是综合网上关于web.xml的一些介绍,希望对大家有所帮助,也欢迎大家一起讨论. ---题记 一. Web.xml详解: (一) web.xml加载过程(步骤) 首 ...
- Maven-pom.xml详解
(看的比较累,可以直接看最后面有针对整个pom.xml的注解) pom的作用 pom作为项目对象模型.通过xml表示maven项目,使用pom.xml来实现.主要描述了项目:包括配置文件:开发者需要遵 ...
- 【maven】 pom.xml详解
pom.xml详解 <project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www ...
- build.xml详解
build.xml详解1.<project>标签每个构建文件对应一个项目.<project>标签时构建文件的根标签.它可以有多个内在属性,就如代码中所示,其各个属性的含义分别如 ...
- 【转】maven核心,pom.xml详解
感谢如下博主: http://www.cnblogs.com/qq78292959/p/3711501.html maven核心,pom.xml详解 什么是pom? pom作为项目对象模型.通过 ...
- C#中的Linq to Xml详解
这篇文章主要介绍了C#中的Linq to Xml详解,本文给出转换步骤以及大量实例,讲解了生成xml.查询并修改xml.监听xml事件.处理xml流等内容,需要的朋友可以参考下 一.生成Xml 为了能 ...
- Ant 之bulid.xml详解
ANT build.xml文件详解(一) Ant的概念 可能有些读者并不连接什么是Ant以及入可使用它,但只要使用通过Linux系统得读者,应该知道 make这个命令.当编译Linux内核及一些软件的 ...
- Tomcat配置(二):tomcat配置文件server.xml详解和部署简介
*/ .hljs { display: block; overflow-x: auto; padding: 0.5em; color: #333; background: #f8f8f8; } .hl ...
- Tomcat(二):tomcat配置文件server.xml详解和部署简介
Tomcat系列文章:http://www.cnblogs.com/f-ck-need-u/p/7576137.html 1. 入门示例:虚拟主机提供web服务 该示例通过设置虚拟主机来提供web服务 ...
随机推荐
- RAC DBCA 找不到共享磁盘
(一) 前言: 通过vmware workstation 走iscsi协议.安装RAC 集群架构,DBCA 时不能识别ASM 共享存储(按理来说这一版都是权限的问题).同一时候,本想通过RMAN ...
- #include”* .h“ 在查找预编译头使用时跳过
warning C4627: “#include <windows.h>”: 在查找预编译头使用时跳过 解决办法: 原因是没有在cpp文件最前一行添加没有添加 #include &quo ...
- html5引擎开发 -- 引擎消息中心和有限状态机 - 初步整理 一
一 什么是有限状态机 FSM (finite-state machine),又称有限状态自动机,简称状态机,是表示有限个状态以及在这些状态之间的转移和动作等行为的数学模型.他对于逻辑以及 ...
- input 监听输入事件
$("#" + inputId).on("input", function () { var checkboxId = $("#" + in ...
- Android 6.0启动过程具体解析
在之前的一篇文章中.从概念上学习了Andoird系统的启动过程.Android系统启动过程学习 而在这篇文章中,我们将从代码角度细致学习Android系统的启动过程,同一时候,学习Android启动过 ...
- webpack2.0简单配置教程
以前习惯用gulp+less来开发项目,由于公司项目用的vue开发的,所以学下webpack这个打包工具.以下是我学习时的笔记,希望给在webpack配置过程中遇到麻烦的朋友一丝帮助. 目前只配置了s ...
- Windows 端口占用
1.netstat -ano | findstr "80"( 80为提示被占用的端口): 2.tasklist | findstr "5584"(5584是从上 ...
- Linux hwclock 命令
hwclock 即 Hardware Clock 硬件时钟,该命令用于查询或设置硬件时钟:硬件时钟是指主机板上的时钟设备,也就是通常可在 BIOS 画面设定的时钟:系统时钟是指 Kernel 中的时钟 ...
- 关于ArrayList和List的区别
ArrayList可以存放不同类型的数据,第一个可以是int,第二个可以是double等等 而List存放的是单一的数据类型的数据用法如下: List<GameObject> xx = n ...
- 《C++ Primer Plus》第11章 使用类 学习笔记
本章介绍了定义和使用类的许多重要方面.一般来说,访问私有类成员的唯一方法是使用类方法.C++使用友元函数来避开这种限制.要让函数称为友元,需要在类声明中声明该函数,并在声明前加上关键字friend.C ...