XML是一种标记语言。
Extensible markup language(可扩展标记语言)
HTML: hyper text markup language(超文本标记语言):其标签已经预定义好了,不能随便定义,或者定义了也没有意义,浏览器不认识。
HTML被设计:显示数据。
XML被设计:传输数据。
WEB开发: Server / Browser(client) ,在大部分情况下都是server服务器 向 客户端 传输数据。
http协议:应用层协议。其实传输的都是纯文本。。。二进制(图片视频等)、字符等等,他们在浏览器端是怎么组织起来显示的呢?通过HTML。。。
从这里看来,html的特点是给浏览器数据加显示的格式。
作用一:XML就可以只传输数据,不传输格式。
作用二:通过自定义标签,来表示结构化的数据,通常用作配置文件。
XML的特点:标签没有预定义,需要用户自己预定义,但是他有一个通用的格式,只有满足这个格式规范,才能正确解析XML文件。
传输数据的格式:
server端数据给到前端 使用纯文本格式。可以是键值对,但键值对只能表示一一对应的关系,无法表示比较复杂的关系。
可以是分隔符:============
但是这样有一个问题:这些方法,都无法用一个通用的解析方式来解析,然后显示在前端。
所以引入XML,XML就是一种通用的用来描述层次结构数据的格式。
数据接口:可以得到需要的一些数据
在许多高级框架中,很多配置文件都是用XML书写的。
HTML 和 XML 的异同:
1.共同点:都是标记语言,都有标签
2.不同点:xml语法严格 , html语法不严格 ;
传输数据 显示数据
可以扩展 已预订好了
严格区分 不区分大小写
标签必须闭合 可以不闭合
只有一个根节点 可有多个根节点
不忽略空格 解析不忽略,显示时忽略
属性值必须加引号 可以不用引号
2.XML语法:
解析的方式是按照:DOM树(忘了回去看...)
<北京>
<朝阳></朝阳>
<海淀></海淀>
</北京>
组成:
文档声明
元素
属性
注释
声明:声明必须出现在文档的第一行
最简单的语法:<?xml version="1.0"?>
encoding="UTF-8"..
元素:指XML文件中出现的标签。
1.标签必须闭合,但如果标签内没有主体,则可以这样写<mytag/>=<mytag></mytag>
2.可以嵌套若干子标签,不允许交叉嵌套。
3.一个XML 有且仅有一个 根标签(HTML则不一样,HTML可以不需要<html></html>)
4.XML中 不会忽略主体中的 空格 和 换行。
5.元素(<标签>)命名规范:
1.严格区分大小写 2.字母和下划线开头 3.不能用保留字(xml/XML) 4.名称字符间不能有空格或tab,也不能用:(':'有特殊用途)
元素属性:
可以有任意个,属性值要用''或""包起来。
命名规范参考元素的命名规范。
在XML计数中,标签的属性所代表的信息 可以被改成 用子元素的形式来描述。
<mytag>
<name fname="hei" lname="ha"></name>
</mytag>
等价于:
<mytag>
<name>
<fname>hei</fname>
<lname>ha</lname>
</name>
</mytag>
注释:
同HTML<!-- 注释 -->
CDATA : 把标签当做普通文本。
<![CDATA[<cskaoyan>www.cccc.com</cskaoyan>]]>
特殊字符:
& / < / > / " / '
处理指令:
以 <? 开头, 以 ?> 结尾
3.XML约束
由于标签可以随意扩展,但是从逻辑上来看,有一些拓展的标签时不合理的,所以需要制定一个规范,也就是XML约束。
约束也是以一个文档的形式书写:
两个概念:格式良好的XML:遵循XML语法
有效的XML:符合约束和语法规范的xml文件。
约束文档规定了,元素名称、属性、书写顺序。(那么就可以通过这些信息来进行解析,可以不知道XML文件)
常用的约束计数:
W3C官方推荐的约束:XML DTD、XML Schema(这两个规范基本现在是并行的)
XML DTD :
Document Type Definition(文档类型定义)
作用:约束XML的书写规范。
.dtd文件
<?xml version="1.0" encoding="UTF-8" ?>
<!ELEMENT bookshelf (books+)>
<!ELEMENT books (bookname,author,price)>
<!ELEMENT bookname (#PCDATA)>
<!ELEMENT author (#PCDATA)>
<!ELEMENT price (#PCDATA)>
XML文件中:
<books>
<bookname></>
<author>哈哈</>
<price>29</>
</books>
IDEA和浏览器都可以判断这个XML是否符合某个dtd约束。
IDEA 在XML打开的窗口中右键——>Validate
浏览器:IE有自带插件可以解析,不过需要写一个脚本来启动这个插件。
约束的出现位置:
1.写在独立的dtd文件里面(常用)
2.写在XML文件里面。
<!DOCTYPE 根元素[
约束文件内容
]>
dtd文档在本地:<!DOCTYPE 根元素 SYSTEM "相对路径">(要在同级目录)
dtd文档在网络:<!DOCTYPE 根元素 PUBLIC "DTD名称" "DTD文档的URL">
(确保此文档不会被修改)更常见
XML和tdt的根元素确保一致。
约束语法细节:(不要求会写)
1.定义元素的约束
<!ELEMENT 元素名 使用规则>
使用规则:
(#PCDATA)纯文本,不能出现子节点,可以为空
EMPTY:指元素主体为空。
ANY:用于指示元素的主体内容任意,包括有子节点等。
(子元素):指示元素中包含的子元素,且子元素的顺序和声明必须一致。
(a,b,c) 每个元素只能出现一次,且按顺序
((a|b),c) a,b任选一个,c出现一次
(a+):表示出现一次或者多次
(a*): 出现任意次
(a?): 出现1次或者0次。
2.定义属性的约束:
<!ATTLIST 元素名
属性名1 属性值类型 设置说明
属性名2 属性值类型 设置说明
属性名3 属性值类型 设置说明
>
属性值类型:
1.CDATA:普通纯文本(可以为空)
2.枚举:只能从枚举列表中任选其一,如(鸡肉|牛肉|猪肉|鱼类)
3.ID:表示属性的取值不能重复(不能写直接值) ,一般跟 #REQUIRED。
设置说明:
#REQUIRED:表示该属性必须出现。
#IMPLIED:表示属性可有可无。
#FIXED:取值只能是某而过固定值,语法:#FIXED "固定值"
直接值:表示该属性的默认值。
XML解析:
解析方式:
1.DOM方式:
Document Object Model 文档对象模型 ,是W3C推荐的方式。
2.SAX方式:
Simple API for XML ,属于开源社区的XML-DEV
类库:(都是为了解析XML)
JAXP:Java API for XML Processing
是SUN公司推出的解析标准
Dom4J:
是开源阻止推出的解析开发包
DOM解析:
JAXP:
passers包 的 DocumentBuilder类(抽象类),不过他自带一个newInstance()方法,返回一个XML的文档对象模型(DOM树)
由两个包组成:
org.w3c.dom:提供DOM方式解析XML的标准接口
javax.xml:提供了解析XML文档的实现类
(这次就是W3C主导制定标准,各种语言厂商自己实现。)
解析book.xml,获取第一本书的名字:
main(){
//获取DOM树,一套规范流程。
DocumentBuilderFactory factory = DocumentBuilderFactory.newInstance();
DocumentBuilder documentBuilder = factory.newDocumentBuilder();
Document dom = documentBuilder.newDocument();
Document dom = builder.parse("xxx.xml");
这个dom就是我们的dom树对象
//解析
//返回一个List
NodeList books = dom.getElementsByTagName("book")
//得到第一本书的节点
Node item = books.item(0);
//回顾一下节点的各种属性
//nodetype/nodename/nodevalue
Node booknameNode = item.getChildNodes().item(1);//拿到<书名>(因为有一个回车作为第一个节点)
String bookname = booknameNode.getChildNodes().item(0).getNodeValue();//拿到书名的文本节点,即书名aaa
改一下:
强转,
Element booknameNode =(Element)item.getChildNodes().item(1);
可以使用Element类中的方法:主要可以操作 节点属性
所以可以参考一下:Attr/Element/Text 的一些独特的方法,简化操作过程
}
用DOM解析编程:
1.得到某个具体的节点内容:获取第二本书的价格
String price = dom.getElementByTagName("售价").item(1).getFirstChild().getNodeValue();
2.打印某个节点的所有元素节点:第三本书的所有节点
NodeList childNodes1 = dom.getElementByTagName("书").item(2).getChildNodes();
3.修改某个元素节点的主体内容
如果想要将修改结果保存在xml文件中,
Transformer 类 用于把XML文件的DOcument对象 更新到 磁盘的文件中:
TransformerFactory.newInstance();
4.向指定元素节点中增加子元素节点:给第一本书增加一个作者。
//先创建一个元素节点<作者></作者>
Element authorElement = dom.createElement("作者");
authorElement.setTextContent("吴军");
//找到第一本书,增加上去
dom.getElementByTagName("书").item(0).appendChild(authorElement);
//标准写回语句 Transformer
5.向指定的元素节点上增加同级元素节点:第二本书的书名之后增加ISBN
Element ISBNElement = dom.createElement("ISBN");
Node secondBookNode = dom.getElementByTagName("书").item(1)
Node child = secondBookNode.getChildNodes().item(3);
secondBookNode.insertBefore(ISBNElement,child)
6.删除指定元素节点:删除最后一本书的售价()
Node lastbook = do...("书").item(3);
Node price = lastbook.getChildNodes().item(3);
lastbook.removeChild(price);
7.操作XML文件属性
。。。
更新文档对象:
如果想要将堆XML文件的修改内容从内存保存到磁盘中,需要通过如下步骤:
TransformerFactory tsf =TransformerFactory.newInstance();
Transformer tsTransformer = tsf.newTransformer();
tsTransformer.transform(
new DOMSource(dom),
new StreamResult("employee.xml"));
XML约束之Schema:
为了克服 DTD约束的局限性。
对比:
1.Schama 符合XML语法结构。
2.DOM、SAX等XML API很容易解析出XML Schema文档中的内容。
3.Schema对 名称空间 支持的非常好(命名空间nameSpace:package(包))
(对同一个名字,加前缀(包名)来区分同名)
约束引入名字空间,用以解决元素的名字冲突。
4.比DTD支持更多的 数据类型 ,并支持用户自定义新的数据类型。
5.Schema 不能像DTD一样定义实体,比DTD更复杂,但XML Schema现在正在逐渐取代,DTD。
Schema 约束规则:
1.Schema文件自身就是一个XML文件,后缀.xsd。
2.schema文档通常称为 模式文档 ,遵循这个文档书写的xml文件称为 实例文档。
和XML文件一样,一个XML Schema文档也必须有根节点,但这个根节点的名称为schema。
入门案例:
约束文档:(book.xsd)
<?xml version="1.0" encoding="UTF-8" ?>
<xs:schema //xs是名称空间的别名
xmlns:xs=“http://www.w3.org/2001/XMLSchema” //标准的名称空间
targetNamespace=“http://www.cskaoyan.com” //将该schema文档绑定到http://www.cskaoyan.com名称空间
elementFormDefault="qualified">
<xs:element name='书架' >
<xs:complexType>
<xs:sequence maxOccurs='unbounded' >
<xs:element name='书' >
<xs:complexType>
<xs:sequence>
<xs:element name='书名' type='xs:string' />
<xs:element name='作者' type='xs:string' />
<xs:element name='售价' type='xs:string' />
</xs:sequence>
</xs:complexType>
</xs:element>
</xs:sequence>
</xs:complexType>
</xs:element>
</xs:schema>
约束文档中出现2个名称空间:
1.xmlns:xs(标准名称空间)、targetNamespace
因为约束文件(.xsd)本身是一个XML文件,所以约束文件的书写也要符合W3C的约束标准(模板)。
xs:...(表明要符合W3C的约束)
targetNamesoace : 用来解决命名冲突的 URI
name='书架'...这些就是符合targetNamespace
实例文档:
<?xml version="1.0" encoding="UTF-8"?>
<cskaoyan:书架
xmlns:cskaoyan="http://www.cskaoyan.com" //cskaoyan是一个别名,可以随意,后面的URI用于绑定 对应的约束 的 .xsd文件。
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" //用到另一个命名空间
xsi:schemaLocation="http://www.cskaoyan.com book.xsd"> //声明引入一个命名空间的约束文件的位置(约束的URI 文件名(同级目录下))。
<cskaoyan:书>
<cskaoyan:书名>做最好的自己</cskaoyan:书名>
<cskaoyan:作者>李开复</cskaoyan:作者>
<cskaoyan:售价>28.00元</cskaoyan:售价>
</cskaoyan:书>
</cskaoyan:书架>
名称空间的概念:
在XML Schema中,每个约束模式文档都可以被赋以一个唯一的名称空间,名称空间用一个唯一的URI(Uniform Resource Identifier,统一资源标识符)表示。
在Xml文件中书写标签时,可以通过名称空间声明(xmlns),来声明当前编写的标签来自哪个Schema约束文档。如:
<cskaoyan:书架 xmlns:cskaoyan=“http://www.cskaoyan.com”>
<cskaoyan:书>……</cskaoyan:书>
</cskaoyan:书架>
此处使用cskaoyan来指向声明的名称,以便于后面对名称空间的引用。
注意:名称空间的名字语法容易让人混淆,尽管以 http:// 开始,那个 URL 并不指向一个包含模式定义的文件。
事实上,这个 URL:http://www.cskaoyan.com根本没有指向任何文件,只是一个分配的名字。
使用名称空间引入Schema
为了在一个XML文档中声明它所遵循的Schema文件的具体位置,通常需要在Xml文档中的根结点中使用schemaLocation属性来指定,例如:
<cskaoyan:书架 xmlns:cskaoyan="http://www.cskaoyan.com"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation=“http://www.cskaoyan.com book.xsd
http://www.cskaoyan.com otherbook.xsd...
">
schemaLocation此属性有两个值。第一个值是需要使用的命名空间。第二个值是供命名空间使用的 XML schema 的位置,两者之间用空格分隔。
注意,在使用schemaLocation属性时,也需要指定该属性来自哪个命名空间。
可以使用默认的名称空间:xmlns="URI",没有别名,则标签中所有没有前缀的,都是默认名称空间的约束
约束的具体规则:
查看W3C文档。W3school的Schema
数据类型/属性类型
XML解析方式之二:SAX解析
好处:
1.在使用 DOM 解析 XML 文档时,需要读取整个 XML 文档,在内存中构架代表整个 DOM 树的Doucment对象,从而再对XML文档进行操作。
此种情况下,如果 XML 文档特别大,就会消耗计算机的大量内存,并且容易导致内存溢出。
而 SAX解析允许在读取文档的时候,即对文档进行处理,而不必等到整个文档装载完才会文档进行操作。
如果不知道XML文件的解析的格式,我们该如何解析???
通过回调来解析
SAX采用事件处理的方式解析XML文件,利用 SAX 解析 XML 文档,涉及两个部分:解析器和事件处理器:
解析器可以使用JAXP的API创建,创建出SAX解析器后,就可以指定解析器去解析某个XML文档。
解析器采用SAX方式在解析某个XML文档时,它只要解析到XML文档的一个组成部分,
都会去调用事件处理器的一个方法,解析器在调用事件处理器的方法时,会把当前解析到的xml文件内容作为方法的参数传递给事件处理器。
事件处理器 由程序员编写,程序员通过事件处理器中方法的参数,就可以很轻松地得到sax解析器解析到的数据,从而可以决定如何对数据进行处理。
代码:
//使用SAXParserFactory创建SAX解析工厂
SAXParserFactory spf = SAXParserFactory.newInstance();
//通过SAX解析工厂得到解析器对象
SAXParser sp = spf.newSAXParser();
//通过解析器对象得到一个XML的读取器
XMLReader xmlReader = sp.getXMLReader();
//设置读取器的事件处理器(看看setContentHandler里面传什么参数,是一个 接口,那我们直接找他的实现类)
xmlReader.setContentHandler(new BookParserHandler());
//解析xml文件
xmlReader.parse("book.xml");
class MyBookHandler extends DefaultHandler{
//回调方法,解析到文档开始的地方
public void startDocument() {
}
//解析器解析到文档介绍的时候
public void endDocument(){
}
//当解析到元素开始节点时,开始回调
StartElement(String uri,String localName,String qName,Attribute attribute){
//qName ——标签全名、uri和localName不会显示
}
//元素结束
public void endElement (String uri, String localName, String qName)
throws SAXException{
// no op
}
//当解析到文本节点的时候,会把文本的内容通过参数传递进来
characters(char[] ch,int start,int length){
String string = new String(ch,start,length);
//这样就就文本节点组装起来了
}
}
这个运行的话流程:会按照你XML文档的顺序解析。只要有这5个方法都存在。。。
这种方式的 增删查改 如果按照DOM树的方法来做,会非常麻烦。
Sax VS Dom :
1.sax优点:节省内存。没法使用sax 解析过程去修改xml文件。
2.sax解析器是基于回调的方法,类似 servlet。
Sax的通常用法:
每次都要扫一遍整个xml,然后将整个xml放入一个list,然后再查找自己需要的东西。
DOM4J 解析:
JAXP提供的dom解析API。dom4j使用接口的抽象基类,但是dom4j没有按照w3c的规范来实现,但是比JDOM更好,更灵活。
优点:性能优异、功能强大、极易使用。
上代码:
(1)创建SAXReader的对象reader
SAXReader reader = new SAXReader();
(2)通过reader对象的read方法加载book.xml文件,获取document对象
Document document = reader.read(new File("src/res/book.xml"));
(3)通过document对象获取根节点bookstores(DOM树)
Element bookStore = document.getRootElement();
去除了文本节点的子节点列表:
List<Element> elements = bookStore.elements();
Element firstBook = elements.get(0);//拿到第一本书
firstBook.elements.get(0);//拿到书名节点
= firstBook.elements.get(1);//拿到作者节点
(4)通过element独享的elementIterator方法获取迭代器
Iterator it = bookStore.elementIterator();
(5)遍历迭代器,获取根节点中的信息(书籍)
while(it.hasNext()){
Element book = (Element)it.next();
获取book的属性名和属性值
List<Attribute>bookAttrs = book.attribute();
遍历每本书中的所有节点
for (Attribute attr : bookAttrs){
获取属性名
attr.getName();
获取属性值
attr.getValue();
(6)标准的写回语句
1.文档中全为英文,不设置编码,直接写入的形式.
XMLWriter writer = new XMLWriter(new FileWriter("output.xml"));
writer.write(document);
writer.close();
2.文档中含有中文,设置编码格式写入的形式.
OutputFormat format = OutputFormat.createPrettyPrint();// 指定XML编码
format.setEncoding("GBK");
XMLWriter writer = new XMLWriter(new FileOutputStream ("output.xml"),format);//format格式,可以让xml看起来很紧凑、
writer.write(document);
writer.close();
}
}
上述为基本用法,下面就是功能体现:Xpath
导包:javaxen.jar
Xpath是一个规范,
我们在使用基本用法的时候,都是基于查询的。
XPath的语法: /开头,表示绝对路径
//开头:表示满足// 之后的所有元素
*:表示选择所有由 * 之前的路径所定位的元素 /*/*/*/BBB :表示在第三级目录下的BBB,不会找第四级目录下的BBB
/AAA/BBB[1]:表示选择此目录下的第一个BBB
/AAA[@id]:表示选择包含 id属性 的AAA
//找第一本书的作者
root.selectSingleNode("/书架/书/作者[1]");可能会变红,但是可以运行
DOM树的注意点:
<?xmlversionxmlversion="1.0" encoding="UTF-8" ?> <书架>
<书>
<书名>魔兽世界法师攻略</书名>
<作者>皮卡丘</作者>
<售价>100.00</售价>
</书>
<书>
<书名>魔兽世界萨满攻略</书名>
<作者>杰尼龟</作者>
<售价>100.00</售价>
</书>
</书架>
XML中,只有 属性、备注、文本,这几种节点才有nodeValue。
而文本,不是 “<书名>魔兽世界法师攻略</书名>”这个东西,
而是<书名>这个节点之内还有一个文本节点是:
“魔兽世界法师攻略”
比如有节点为:
<书名>魔兽世界<强调>法师</强调>攻略</书名>
那么书名下面有三个字节点,分别为:
文本节点:魔兽世界
元素节点:<强调>
文本节点:攻略
得到文本值:
System.out.println(list.item(0).getFirstChild().getFirstChild().getNodeValue());
或者:
System.out.println(list.item(0).getFirstChild().getTextContent())