1 xml的简介 w3c组织发布
extensible markup Language :可扩展标记型语言 也是使用标签操作
可扩展:html里面的标签是固定,每个标签都有特定的含义
xml标签可以自己定义,可以写中文的标签
用途:显示数据(不是主要功能) ,主要为了存储数据
两个版本:1.0 1.1 使用的都是1.0版本(1.1不能向下兼容)
2 xml的应用
不同系统之间传输数据
用来表示生活中有关系的数据
经常用在文件配置
比如现在连接数据库,肯定得知道数据库的用户名和密码,数据名称
如果修改数据库的信息,不需要修改源代码,只要修改配置文件就可以
3 xml的语法
1 xml的文档声明 后缀名为.xml 如果写xml,第一步必须要有一个文档声明(写了文档声明之后,表示写xml文件的内容)
<?xml version="1.0" encoding="gbk"?>
文档声明必须写在第一行第一列
属性:version :xml的版本 encoding:xml编码 gbk utf-8 iso8859-1(不包含中文)
standalone : 是否依赖其他文件存在
xml问题的解决:保存时候的编码和设置打开时的编码一致,不会出现乱码
2 定义元素(标签)
3 定义属性
4 特殊字符
5 CDATE区
6 PI指令
7 注释
5 xml元素的定义
标签定义 例:<person></person> 标签有开始必须要有结束
标签没有内容,可以在标签内结束:<aa/>
标签可以嵌套,但必须合理嵌套
一个xml中只能有一个根标签,其他标签都是这个标签下面的标签
注意:在xml中把空格和换行都当成内容来解析
<aa>AAAAA</aa>
<aa>
AAAA
</aa>
以上两端代码含义不一样
xml中标签的名称规则
1 xml区分大小写
<P><p> 这两个标签是不一样的
2 xml的标签不能以数字和下划线开头
3 xml的标签不能以xml ,XML.Xml等开头 <Xmla><Xmlb><xmlc> :这些都是不正确的
4 xml的标签不能包含空格或冒号 <a b><b:c>:这些是不正确的
6 xml中属性的定义
<person id1="aaa"> </person>
属性定义的要求
1 一个标签可以有多个属性
2 属性名称不能相同
3 属性名称和属性值之间使用= 属性值使用引号包起来(可以使用单双引号)
4 xml属性名称规范与元素规范是一致的
7 xml中的注释
写法<!-- -->
注意:注释不能有嵌套
8 xml中的特殊字符
如果想要在xml中显示 a<b 不能正常显示,因为把<当做标签
需要转义:&: & <: < > : > " : " ' : ' (后面需要;号)
9 CDATA区
可以解决多个字符都需要转义的操作
把这些内容放到CDATA区里面,不需要转义
写法<![CDATA[ 内容 ]]>
例<![CDATA[ <b>if(a<b && b<c && d>f) {}</b> ]]>
把特殊字符,当做文本内容,而不是标签
10 PI指令(处理指令)
可以在xml中设置样式
写法:<?xm-stylesheet type="text/css" href="css的路径"?>
设置样式,只能对英文标签名称起作用,对于中文的标签名称不起作用
11 语法总结
所有xnl元素都必须有关闭标签
xml标签对大小写敏感
xml必须有正确的嵌套顺序
xml文档必须有根元素(只有一个)
xml的属性值必须加引号
特殊字符必须转义 ---CDATA
xml中的空格,回车换行在解析时会被保留
12 xml的约束
为什么需要约束?规定xml中只能出现的元素,这个时候需要约束
xml的约束的技术:dtd约束和schema约束
13 dtd的快速入门
创建一个文件 后缀名 .dtd
步骤: 1 看xml中有多少个元素,有几个元素,在dtd文件中写几个<!ElEMENT>
2 判断元素是简单元素还是复杂元素
复杂元素:有子元素的元素 <!ELEMENT 元素名称 (子元素)>
简单元素: 没有子元素 <!ELEMENT 元素名称 (#PCDATA)>
3 需要在xml文件中引入dtd文件
<!DOCTYPE 根元素名称 SYSTEM "dtd文件的路径">
打开xml文件使用浏览器打开的,浏览器只负责校验xml的语法,不负责校验约束
如果想要校验xml的约束,需要使用工具(myeclipse工具)
14 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”> (框架structs2 使用的方式)
15 使用dtd定义元素
语法:<!ELEMENT 元素名 约束>
简单元素:<!ELEMENT name (#PCDATA)> (#PCDATA):约束name是字符串类型
EMPTY: 元素为空 (没有内容)(不用加括号)
ANYY: 任意元素
复杂元素:<!ELEMENT person (name,age,sex)> 各元素只能出现一次
表示子元素出现的次数
+:表示一次或者多次
?;表示零次或者一次
*:表示零次或者多次
子元素直接使用逗号进行隔开:表示元素出现的顺序
子元素直接使用|隔开:表示元素只能出现其中的任意一个
16 使用dtd定义属性
语法:<!ATTLIST 元素名称
属性名称 属性类型 属性约束
>
属性类型:CDATA::字符串 枚举:(aa|bb|cc) 表示只能在一定范围内出现值,但是只能每次出现其中一个
ID :值只能是字母或者下划线卡头
属性的约束:#REQUIRED :表示该属性必须出现
#IMPLIED:属性可有可无
#FIXED:表示一个固定的一个值 例:#FIXED "AAA" 属性的值必须是设定的这个值
直接值: 例:"WWW" 不写属性,使用直接值,写了属性,使用设置的值
17 实体的定义
语法<!ELEMENT 实体名称 “实体的值”> 引用实体 &实体名称
定义实体需要写在内部dtd里面,如果写在外部的dtd里面,在某些浏览器下,内容得不到
18 xml的解析的简介
xml的解析方式:dom 和 sax
dom:根据xml的层级结构在内存中分配一个树形结构,把xml的标签,属性和文本都封装成对象
缺点:如果文件过大,造成内存溢出
优点:很方便实现增删改操作
sax方式解析
采用事件驱动,边读边解析,从上到下,一行一行的解析,解析到某一个对象,返回对象名称
缺点:不能实现增删改操作
优点:如果文件过大,不会造成内存溢出,方便实现查询操作
想要解析xml,首先需要解析器
不同的公司和组织提供了针对dom和sax方式的解析器,通过api方式提供
sun公司提供了针对dom和sax解析器 jaxp
dom4j组织:dom4j jdom组织:jdom
19 jaxp的api查看
jaxp是javase的一部分
jaxp解析器在jdk的javax.xml.parseers包里面
四个类:分贝针对dom和sax解析使用的类
dom: DocumentBuilder :解析器类 这个类是一个抽象类 不能new 此类的实例
DocmentBuilderFactory.newDocumentBuilder()方法获取 DocmentBuilderFactory :也是一个抽象类 通过newInstance() 获取DocumentBuilderFactory获取实例
parse(”xml路径“) 返回的是Document整个文档 返回的docunment是一个接口,父节点是Node,如果在docunment找不到方法,可以到Node去找
在document里面的方法
getElementsByTagName(String tagname) 这个方法可以得到标签 返回集合NodeList
createElement(String tagname) 创建标签
createTextNode(String data) 创建文本
appendChild(Node newChild) 把文本添加到标签下面
removeChild(Node oldChild) 删除节点
getParentNode() 获取父节点
NodeList 方法: getLength() 可以得到集合的长度 item(int index) 下标取到具体的值
sax: SAXParser:解析器类 SAXParseFactory:解析器工厂
20 使用jaxp实现查询操作
查询xml中所有的name元素的值
* 1 创建解析器工厂 DocumentBuilderFactory builderFactory = DocumentBuilderFactory.newInstance();
* 2 根据解析器工厂创建解析器 DocumentBuilder builder = builderFactory.newDocumentBuilder();
* 3 解析xml返回document Document document = builder.parse("src/1.xml");
* 4 得到所有的name元素
21 使用jaxp添加节点
在第一个标签下面添加一个节点
步骤:
*1 创建解析器工厂 2 根据解析器工厂创建解析器 3 解析xml返回document
* 4 得到第一个标签 使用item方法
* 5 创建sex标签createElement
* 6 创建文本createTextNode
* 7 把文本添加到sex下面appChild
* 8 把sex添加到第一标签下面
* 9 回写xml
回写代码:TransformerFactory transformerFactory = TransformerFactory.newInstance();
Transformer transformer = transformerFactory.newTransformer();
transformer.transform(new DOMSource(document), new StreamResult("src/1.xml"));
22 使用jaxp修改节点
修改标签下面的内容
修改方法 setTextContent方法
23 使用jaxp删除节点
得到父节点,之后进行删除操作 removeChild()
24 使用jaxp遍历节点
把xml所有元素的名称都打印出来
递归实现:
private static void List1(Node node) {
//判断是元素类型时候打印
if(node.getNodeType() == Node.ELEMENT_NODE){
System.out.println(node.getNodeName());
}
//得到一层字节点
NodeList list = node.getChildNodes();
for(int i =0;i<list.getLength();i++){
//得到每一个节点
Node node1 = list.item(i);
List1(node1);
}
}
23
schema约束
schema符合xml的语法,xml语句
一个xml中可以有多个schema,多个schema使用名称区间划分(类似于java包名)
dtd里面有PCDATA类型,但是在schema里面可以支持更多的数据类型 比如 年龄 只能是整数,在schema可以直接定义一个整数类型
schema语法更加复杂,schema目前不能替代dtd
24 schema的快速入门
创建一个schema文件 后缀名是.xsd 根节点<schema>
在schema文件里面
属性: xmlns="http://www.w3.org/2001/XMLSchema" 表示当前xml文件是一个约束文件
targetnamespace="http://www.itcast.cn/20151111" 使用schema约束文件,直接通过这个地址引入约束文件
elementFormDefault="qualified"
步骤 1 看xml有多少个元素 <element>
2 看简单元素和复杂元素
如果复杂元素
<complexType>
<sequence> 子元素</sequence>
</complexType>
3 简单元素写在复杂元素里面
<element name="person">
<complexType>
<sequence>
<element name="name" type="string"></element>
<element name="age" type="int"></element>
</sequence>
</complexType>
</element>
4 引入文件
<person xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" 表示是一个被约束文件(由于有两个xmlns所以自己再起一个别名:xsi)
xmlns="http://www.itcast.cn/20151111" 是约束文档里面 targetNamespace
xsi:schemaLocation="http://www.itcast.cn/20151111 1.xsd"> targetNamespace 空格 约束文档的路径
25 <sequence> 表示元素出现的顺序
<ALL> 表示只能出现一次
<choice>::表示元素只能出现其中一个
maxOccurs="unbounded":表示元素出现的次数
<any></any>:表示任意元素
可以约束属性
写在复杂元素里面,</complexType>之前
<attribute name="id1" type="int" use="required"></attribute>
name:属性名称 type:属性类型 int string use:属性是否必须出现 required
复杂schema 元素前加: schema别名(自己起的):
26 sax解析原理:
事件驱动:边读边解析
在javax.xml.parsers包里面
SAXParser
此类的实例可以从SAXParserFactory.newSAXParser() 方法获得
parse(File f,DefaultHandler dh) 两个参数 1 xml的路径 2 事件处理器
SAXParserFactory 实例 newInstance() 方法获得
sax执行过程:
当解析到开始标签的时候,自动执行startElement方法
当解析到文本时候,自动执行characters方法
当解析到结束标签时候,自动执行endElement方法
27 jaxp的sax方式解析xml
sax方式不能实现增删改操作,只能做查询操作
打印出整个文档
执行parse方法,第一个参数xml路径,第二个参数是事件处理器
创建一个类,继承事件处理器的类
重写里面的三个方法
获取到所有的name元素的值
定义一个成员变量,flag = false
判断开始方法是否是name元素,如果是name元素,把flag设置成true
如果为true,在characters方法里面打印内容
当执行到结束方法时,把flag设置成false
获取第一个name元素的值
定义一个成员变量 index = 1;
在结束方法时候,index++
想要打印第一个name元素的值,在characters方法里面判断 判断flag = true 并且index==1,在打印内容
28 使用dom4j解析xml
dom4j,是一个组织,针对xml解析,提供解析器dom4j
dom4j不是javase的一部分,想要使用第一步需要导入dom4j jar包
创建一个文件夹 复制jar包到lib下面 右键点击 jar包 build path---add buildpath (变为奶瓶样子说明导入成功)
得到document
SAXReader reader = new SAXReader();
Document document = reader.read(url);
document的父接口是Node
如果在document里面找不到想要的方法,到Node里面去找
document 里面的方法 getRootElement(): 获取根节点 返回的是Element
Element 也是一个接口 ,父接口是Node
Element 和Node里面方法 getParent() 获取父节点 addElement : 添加标签 element(qName) 表示获取标签下面的第一个子标签 elements(qname) 获取标签下面的是这个名称的所有子标签 elements() 获取标签下面的所有一层子标签
29 使用dom4j 查询xml
解析从上到下
查询所有name元素里面的值
1 创建解析器 2 得到document 3 得到根节点 getRootElement() 返回Element
4 得到所有的p1标签
elements("p1") 表示获取标签下面是这个名称的所有子标签(一层) 返回list集合
遍历list得到每一个p1
5得到name
在p1 下面执行element("name")方法 返回Element
6 得到name里面的值
getText方法得到值
查询第一个name元素的值
1 创建解析器
2 得到document
3 得到根节点
4 得到第一个p1元素 element("p1") 返回Element
5 得到p1下面的name元素
6 得到name元素里面的值
获取第二个name元素的值
1 创建解析器
2 得到document
3 得到根节点
4 得到所有的p1 返回list集合
5 遍历得到第二个p1 使用list下标得到get方法,集合的下标从0开始,想要得到第二个值,下标写1
5 得到p1下面的name元素
6 得到name元素里面的值
30 使用dom4j实现添加操作
在第一个p1标签
*1 创建解析器
*2 得到document
*3 得到根节点
*4 获取第一个p1 使用element方法
*5 在p1 下面添加元素 在p1上面直接使用addElement("标签名称")方法 返回一个Element
*6 在添加完成之后的元素添加文本 在sex直接使用setText("文本内容")方法
*7 回写xml
格式化:OutputFormat,使用 createPrettyPrint方法 表示一个漂亮的格式
使用类XMLWriter 直接new这个类,传递两个参数
第一个参数是xml文件路径 new FileOutputStream("路径")
第二个参数是格式化类的值
31 在特定的位置添加元素
在第一个p1下面的age标签之前添加<school> </school>
*1 创建解析器
*2 得到document
*3 得到根节点
*4 获取第一个p1
*5 获取p1下面所有元素 elements() 方法 返回list集合 使用list方法,在特定位置添加元素
*首先需要创建元素,在创建文本1 Element school=DocumentHelper.createElement("school"); 2 school.setText("ecit");
*3 list.add(1,school);
*add(int index,E element)
*6 回写xml
32 使用dom4j实现修改节点的操作
修改第一个p1下面的age元素的值
* 1 得到document
* 2 得到根节点,然后再得到第一个p1元素 element()
* 3 得到第一个p1下面的age element()
* 4 修改值age setText("文本内容")
* 5 回下xml
33 使用dom4j 实现删除节点
*1 得到document
*2 得到根节点
*3 得到第一个p1标签
*4 得到第一个p1下面的school元素
*5 删除 remove() 首先得先得到父节点 getParent()
*6 回下xml
34 使用dom4j获取属性的值
获取第一个 p1的属性id1的值
*1 得到document
* 2 得到根节点
* 3 得到第一个p1 元素
* 4 得到p1里面属性的值 attributeValue("id1"); 在p1上面操作
35 使用dom4j支持xpath操作
可以直接获取到某个元素
第一种形式 /AAA/DDD/BBB:表示一层一层的,AAA下面DDD下面的BBB
第二种形式 //BBB: 表示和这个名称相同,只要名称是BBB,都得到
第三种形式 /*:所有元素
第四种形式 BBB[1]: 表示第一个BBB元素 BBB[last()] : 表示最后一个BBB元素
第五种形式 //BBB[@id] : 表示只要BBB元素上面有id属性,都得到
第六种形式 //BBB[@id='b1'] 表示元素名称是BBB,在BBB上面有id属性,并且id的属性值是b1
36 使用dom4j 支持xpath具体操作
默认情况下 ,dom4j不支持xpath
需要引入jar包:jaxen-1.1-beta-6.jar
在dom4j里面提供了两个方法,用来支持xpath
selectNodes("xpath表达式") 获取多个节点 selectSingleNode("xpath表达式") 获取一个节点
使用xpath实现:查询xml中所有name元素的值 xpath表示://name
1 得到document
2 直接使用document.selectNodes("//name") 方法得到所有的name元素 返回的是一个list集合
3 遍历list集合 之后使用 getText()方法得到值
使用xpath实现:获取第一个p1下面name的值
1 得到document
2 直接使用selectSingleNode方法实现 xpath://p1[@id1='aaa']/name 返回的是Node
37 实现简单的学生管理系统
使用xml当做数据库,存储学生信息
创建一个xml文件,写一些学生信息
1 增加操作
创建解析器
得到document
获取根节点
在根节点上面创建stu标签
在stu标签上面一次添加id name age addElement方法添加
在id name age 上面一次添加值 setText
回写xml
2 删除操作(根据id删除)
创建解析器
得到document
获取所有的id 使用xpath //id 返回list集合
遍历list集合
判断集合里面的id和传递的id是否相同
如果相同,把id所在的stu删除
3 查询操作(根据id查询)
创建解析器
得到cocument
获取所有的id,返回的是list集合,遍历list集合
得到每一个id的节点的值
判断id的值和传递的值是否相同
如果相同,先获取到id的父亲节点stu
通过stu获取到name age 值 把这些值封装到一个对象里面 返回对象