1.xml基础
1.1 什么是xml
XML是指可扩展标记语言(eXtensible Markup Language),它也是一种标记语言,很类似HTML。它被设计的宗旨是传输数据,而非显示数据。(纯文本、跨平台、可读性强(相对json))
XML标签没有被预定义,需要用户自行定义标签。
XML技术是W3C组织(World Wide Web Consortium万维网联盟)发布的,目前遵循的是W3C组织于2000年发布的XML1.0规范。
XML被广泛认为是继Java之后在Internet上最激动人心的新技术。
1.2 xml文件用来解决什么问题
XML应用于 web 开发的许多方面,常用于简化数据的存储和共享
XML语言出现的根本目的在于描述下图有关系的数据
XML是一种通用的数据交换格式。(跨平台)
在XML语言中,它允许用户自定义标签。一个标签用于描述一段数据;一个标签可分为开始标签和结束标签,在起始标签之间,又可以使用其它标签描述其它数据,以此来实现数据关系的描述
XML中的数据必须通过软件程序来解析执行或显示,如IE;这样的解析程序称之为Parser(解析器)
1.3 xml常见应用
用于数据存储;
用于配置文件.用于描述模块之间的关系(如著名的Mybatis、Spring和SpringMVC都是基于XML作为配置文件的);
用于数据传递.项目之间要交互,需要使用大家都能识别的方式,比如webservice等
2. xml语法
一个xml主要包含以下部分:文档声明,元素,属性,注释,CDATA区,处理指令,Xml约束
2.1 文档申明
1.在编写XML文档时,需要先使用文档声明来声明XML文档。且必须出现在文档的第一行。(前面注释都不允许)
最简单的语法:
2.用encoding属性说明文档所使用的字符编码。保存在磁盘上的文件编码要与声明的编码一致
如:
3.用standalone属性说明文档是否独立,即是否依赖其他文档
如:
2.2 元素
1.XML元素指XML文件中出现的标签。一个标签分为起始和结束标签(不能省略)。一个标签有如下几种书写形式:
包含标签主体:some content
不含标签主体:(有时也叫空标签)
2.一个标签中可以嵌套若干子标签,但所有标签必须合理的嵌套,不允许有交叉嵌套
以上写法是不允许的
3.一个XML文档必须有且仅有一个根标签,其他标签都是这个根标签的子标签或孙标签
4.对于XML标签中出现的所有空格和换行,XML解析程序都会当作标签内容进行处理。例如:下面两段内容的意义是不一样的:
<网址>ww.1000phone.copm</网址>
<网址> ww.1000phone.copm </网址>
5.由于在XML中,空格和换行都作为原始内容被处理,所以,在编写XML文件时,使用换行和缩进等方式来让原文件中的内容清晰可读的“良好”书写习惯可能要被迫改变
6.元素命名规范:一个XML元素可以包含字母、数字以及其它一些可见字符,但必须遵守下面的一些规范:
区分大小写,例如,和是两个不同的标记;
不能以数字或"_" (下划线)开头;
不能以xml(或XML、或Xml 等)开头。(xml 为关键字,所以不能重复);
不能包含空格;
名称中间不能包含冒号(:)
2.3 属性
1.一个元素可以有多个属性,每个属性都有它自己的名称和取值,例如:
2.属性值一定要用引号(单引号或双引号)引起来
3.属性名称的命名规范与元素的命名规范相同
4.元素中属性没有顺序要求,但是不准重复
5.在XML技术中,标签属性所代表的信息也可以被改成用子元素的形式来描述
2.4 注释
XML中的注释语法为:
注意:
XML声明之前不能有注释(xml声明必须放在文档第一行);
注释不能嵌套,例如:
<!--大段注释 … <!—又一大段注释--> … --> 以上的注释方式是错误的,注释不能嵌套!!!
2.5 实体引用
1.在 XML 中,一些字符拥有特殊的意义。如果你把字符 "<" 放在 XML 元素中,会发生错误,这是因为解析器会把它当作新元素的开始。如下这样会产生 XML 错误:
<message>if salary < 1000 then</message>
为了避免这个错误,请用实体引用来代替 "<" 字符:
<message>if salary < 1000 then</message>
在 XML 中,有 5 个预定义的实体引用:
< < 小于 > > 大于 & & 和号 ' ' 单引号 " " 引号
2.6 处理指令(仅了解)
处理指令,简称PI(Processing Instruction)。
作用:用来指挥软件如何解析XML文档
语法:必须以“”作为结尾
常用处理指令:
XML声明:
xml-stylesheet指令:作用:指示XML文档所使用的CSS样式XSLT
使用 CSS 格式化 XML 不是常用的方法,更不能代表 XML 文档样式化的未来
<?xml version="1.0" encoding="ISO-8859-1"?> <?xml-stylesheet type="text/css" href="cd_catalog.css"?>
2.7 xml语法总结
所有 XML 元素都须有关闭标签
XML标签对大小写敏感
XML必须正确地嵌套顺序
XML文档必须有根元素(有且仅有一个)
XML的属性值须加引号
特殊字符必须转
XML中的空格、回车换行会解析时被保留
一份XML文档,最终可以转化为一个树状结构:
3. xml约束(了解)
3.1 为什么需要约束
XML都是用户自定义的标签,若出现小小的错误,软件程序将不能正确地获取文件中的内容而报错
XML技术中,可以编写一个文档来约束一个XML的书写规范,这个文档称之为约束
两个概念:
格式良好的XML:遵循XML语法的XML;
有效的XML:遵循约束文档的XML
总之:约束文档定义了在XML中允许出现的元素名称、属性及元素出现的顺序等等
3.2 什么是xml约束
在XML技术里,可以编写一个文档来约束一个XML文档的书写规范,这称之为XML约束
常用的约束技术XML DTD, XML Schema
作为普通工程师,一般是使用别人的约束文件,而不会自己去写约束。例如使用SSM框架开始时用到的xml文件,均要受框架的提供的xml的约束文件的约束
3.3 DTD约束
3.3.1 什么是DTD约束
DTD(Document Type Definition),全称为:文档类型定义
这里有一份xml文档如下:
<?xml version="1.0" ?> <!DOCTYPE书架 SYSTEM "book.dtd"> <书架> <书> <书名>葵花宝典</书名> <作者>东方不败</作者> <售价>59.00元</售价> </书> <书> <书名>九阳神功</书名> <作者>张无忌</作者> <售价>57.00元</售价> </书> </书架>
为了约束该文档,指定DTD约束如下:
<!ELEMENT 书架 (书+)> <!ELEMENT 书 (书名,作者,售价)> <!ELEMENT 书名 (#PCDATA)> <!ELEMENT 作者 (#PCDATA)> <!ELEMENT 售价 (#PCDATA)>
3.3.2 xml引用DTD
DTD约束即可以作为一个单独的文件编写,也可以在XML文件内编写
第一种:使用内部DTD,如下:
<?xml version="1.0" encoding="UTF-8" standalone="yes"?> <!DOCTYPE 书架 [ <!ELEMENT 书架 (书+)> <!ELEMENT 书 (书名,作者,售价)> <!ELEMENT 书名 (#PCDATA)> <!ELEMENT 作者 (#PCDATA)> <!ELEMENT 售价 (#PCDATA)> ]> <书架> <书> <书名>itjob就业培训</书名> <作者>李xx</作者> <售价>39.00元</售价> </书> ... </书架>
第二种,使用外部本地DTD
当引用的DTD文档在本地时,采用如下方式:如:
第三种,使用公共DTD
如:
<!DOCTYPE web-app PUBLIC "-//Sun Microsystems, Inc.//DTD Web Application 2.3//EN" "http://java.sun.com/dtd/web-app_2_3.dtd">
3.3.3 DTD约束语法
元素定义:
在DTD文档中使用ELEMENT关键字来声明一个XML元素
语法:
使用规则:
(#PCDATA):指示元素的主体内容只能是普通的文本.(Parsed Character Data)
EMPTY:用于指示元素的主体为空。比如
ANY:用于指示元素的主体内容为任意类型
(子元素):指示元素中包含的子元素
定义子元素及描述它们的关系:
a.如果子元素用逗号分开,说明必须按照声明顺序去编写XML文档。如:
b.如果子元素用“|”分开,说明任选其一。如:
c.用+、*、?来表示元素出现的次数:
1.如果元素后面没有+*?:表示必须且只能出现一次
2.+:表示至少出现一次,一次或多次
3.*:表示可有可无,零次、一次或多次
4.?:表示可以有也可以无,有的话只能有一次。零次或一次.如:
如下表:
示例如下:
<!ELEMENT pets (dogs,penguins)>:element用来描述节点 <!ELEMENT dogs (dog*)> dogs节点下可以有任意个数的dog节点(0个,1个或多个) <!ELEMENT penguins (penguin+)>:+表示可以有1个或多个penguin节点 <!ELEMENT dog (name,health,love,strain?)>:?表示strain节点可以有0个或者1个 <!ATTLIST dog id CDATA #REQUIRED>:attlist表示属性,dog节点下必须有一个id属性
4. xml解析
xml解析方式有多种:
DOM:Document Object Model,文档对象模型,DOM是基于XML文档树结构的解析。这种方式是W3C推荐的处理XML的一种方式
jdk自带,不需要额外添加任何jar文件。它把我们的xml文档看成是一棵树,解析的时候,把整棵树读到内存中,可以很方便的获取任意节点,也可以很方便的得到任意节点的父节点或子节点。
缺点是树很大的时候,会比较耗资源,解析过程也略显繁琐
SAX:Simple API for XML。SAX是基于事件流的解析
利用自带的解析器,只针对单个节点解析,没有父子关系.j2ee的开发中很少使用
JDOM解析:是开源组织推出的解析开发包,号称综合了上述两种方式的优点,在j2ee开发中有部分使用
Dom4J解析:是开源组织推出的解析开发包。(是一种实际的标准,大家都在用。包括SUN公司的一些技术的实现都在用)
解析过程最简洁方便,目前主流框架的解析都是使用DOM4J.
Pull解析,一般在移动应用中使用,j2ee开发中比较少
4.1 DOM解析
使用DOM解析器解析一个XML文档时,我们得到一棵结构树,它表示XML文档的内容。所有的文本,元素和属性,都在这个树结构中。解析的过程如下图:
1.DOM以及广义的基于树的处理具有几个优点
首先,由于树在内存中是持久的,因此可以修改它以便应用程序能对数据和结构作出更改。它还可以在任何时候在树中上下导航,而不是像SAX那样是一次性的处理。DOM使用起来也要简单得多
另一方面,在内存中构造这样的树涉及大量的开销。大型文件完全占用系统内存容量的情况并不鲜见。此外,创建一棵DOM树可能是一个缓慢的过程。为了满足该缺点,我们使用SAX(Simple API for XML)API处理XML文档内容。它的设计目标是占用更少的内存,把更多的工作交给程序员。SAX和DOM是互补的,有各自的适用环境
2.解析过程:
javax.xml.parsers包中的DocumentBuilderFactory用于创建DOM模式的解析器对象 , DocumentBuilderFactory 是一个抽象工厂类,它不能直接实例化,但该类提供了一个newInstance方法 ,这个方法会根据本地平台默认安装的解析器,自动创建一个工厂的对象并返回
调用 DocumentBuilderFactory.newInstance()方法得到创建 DOM 解析器的工厂
调用工厂对象的 newDocumentBuilder方法得到 DOM 解析器对象
调用 DOM 解析器对象的 parse() 方法解析 XML 文档,得到代表整个文档的 Document 对象,进行可以利用DOM特性对整个XML文档进行操作了
3.DOM模型(document object model):
DOM解析器在解析XML文档时,会把文档中的所有元素,按照其出现的层次关系,解析成一个个Node对象(节点);
4.在dom中,节点之间关系如下:
位于一个节点之上的节点是该节点的父节点(parent)
一个节点之下的节点是该节点的子节点(children)
同一层次,具有相同父节点的节点是兄弟节点(sibling)
一个节点的下一个层次的节点集合是节点后代(descendant)
父、祖父节点及所有位于节点上面的,都是节点的祖先(ancestor)
5.Node对象
Node对象提供了一系列常量来代表结点的类型,当开发人员获得某个Node类型后,就可以把Node节点转换成相应的节点对象(Node的子类对象),以便于调用其特有的方法。(查看API文档)
Node对象提供了相应的方法去获得它的父结点或子结点。编程人员通过这些方法就可以读取整个XML文档的内容、或添加、修改、删除XML文档的内容了
比如xml文件内容如下:
<?xml version="1.0" encoding="UTF-8"?> <Students> <stu id="1001"> <stuname>zhangsan</stuname> <stuage>20</stuage> <postcode>518000</postcode> </stu> <stu id="1002"> <stuname>lisi</stuname> <stuage>22</stuage> <postcode>518002</postcode> </stu> <stu id="1003"> <stuname>wangwu</stuname> <stuage>21</stuage> <postcode>518001</postcode> </stu> </Students>
要想解析上述xml文档的内容,代码如下:
import java.io.IOException; import java.io.InputStream; import javax.xml.parsers.DocumentBuilder; import javax.xml.parsers.DocumentBuilderFactory; import javax.xml.parsers.ParserConfigurationException; import org.w3c.dom.Document; import org.w3c.dom.Element; import org.w3c.dom.Node; import org.w3c.dom.NodeList; import org.xml.sax.SAXException; /** * DOM解析 * * @author Administrator * */ public class Test { public static void parseXml() { try { // 得到一个解析工厂 DocumentBuilderFactory factory = DocumentBuilderFactory.newInstance(); // 创建解析对象 DocumentBuilder builder = factory.newDocumentBuilder(); // 创建解析文档对象 // File file = new File(文件的绝对路径); InputStream is = Test.class.getResourceAsStream("/stus2.xml"); Document doc = builder.parse(is); // 从文档对象中获取所有的stu节点 NodeList list = doc.getElementsByTagName("stu"); for (int i = 0; i < list.getLength(); i++) { // 获取集合中的某一个stu节点 Node node = list.item(i); // 先得到节点的id属性 Element element = (Element) node; String value = element.getAttribute("id"); System.out.println("id:" + value); // node.getFirstChild(),表示得到node节点的第一个子节点 // child.getNextSibling(),表示得到child的下一个兄弟节点 for (Node child = node.getFirstChild(); child != null; child = child.getNextSibling()) { // 判断节点是否是一个元素节点 if (child.getNodeType() == Node.ELEMENT_NODE) { String nodeName = child.getNodeName(); String nodevalue = child.getFirstChild().getNodeValue(); System.out.println("节点名:" + nodeName + ",节点的文本:" + nodevalue); } } System.out.println("*****************************************"); } } catch (ParserConfigurationException e) { e.printStackTrace(); } catch (SAXException e) { e.printStackTrace(); } catch (IOException e) { e.printStackTrace(); } } public static void main(String[] args) { Test.parseXml(); } }
4.2 DOM4J解析
Dom4j解析器是使用比较广的解析器。在目前流行的技术里面都是用Dom4j解析器来解析xml文档的。如:Hibernate和Spring
Dom4j是一个简单、灵活的开放源代码的库。Dom4j是由早期开发JDOM的人分离出来而后独立开发的。与JDOM不同的是,dom4j使用接口和抽象基类,虽然Dom4j的API相对要复杂一些,但它提供了比JDOM更好的灵活性
Dom4j是一个非常优秀的Java XML API,具有性能优异、功能强大和极易使用的特点。现在很多软件采用的Dom4j,例如Hibernate,包括sun公司自己的JAXM也用了Dom4j
使用Dom4j开发,需下载dom4j相应的jar文件
1.Dom对象
DOM4j中,获得Document对象的方式有三种:
第一种:读取XML文件,获得document对象,代码如下:
SAXReader reader = new SAXReader(); Document document = reader.read(new File("input.xml"));
第二种:解析XML形式的文本,得到document对象:
String text = "<members></members>"; Document document = DocumentHelper.parseText(text);
第三种:主动创建document对象
Document document = DocumentHelper.createDocument(); //创建根节点 Element root = document.addElement("members");
2.节点对象
获取文档的根节点: Element root = document.getRootElement();
取得某个节点的子节点: Element element=node.element(“书名");
取得节点的文字: String text=node.getText();
取得某节点下所有名为“member”的子节点,并进行遍历:
List nodes = rootElm.elements("member"); for (Iterator it = nodes.iterator(); it.hasNext();) { Element elm = (Element) it.next(); // do something }
对某节点下的所有子节点进行遍历
for (Iterator it = root.elementIterator(); it.hasNext();) { Element element = (Element) it.next(); // do something }
在某节点下添加子节点: Element ageElm = newMemberElm.addElement("age");
设置节点文字: element.setText("29");
删除某节点: parentElm.remove(childElm);
添加一个CDATA节点:
Element contentElm = infoElm.addElement("content"); contentElm.addCDATA(diary.getContent());
1、节点对象属性
取得某节点下的某属性:
Element root=document.getRootElement(); //属性名name Attribute attribute=root.attribute("size");
取得属性的文字: String text=attribute.getText();
删除某属性:
Attribute attribute=root.attribute("size"); root.remove(attribute);
遍历某节点的所有属性:
Element root=document.getRootElement(); for(Iterator it=root.attributeIterator();it.hasNext();){ Attribute attribute = (Attribute) it.next(); String text=attribute.getText(); System.out.println(text); }
设置某节点的属性和文字: newMemberElm.addAttribute("name","sitinspring");
设置属性的文字:
Attribute attribute=root.attribute("name"); attribute.setText("sitinspring");
1、将文档些人xml文件
文档中全为英文,不设置编码,直接写入的形式:
XMLWriter writer = new XMLWriter(new FileWriter("output.xml")); writer.write(document); writer.close();
文档中含有中文,设置编码格式写入的形式:
OutputFormat format = OutputFormat.createPrettyPrint(); // 指定XML编码 format.setEncoding("GBK"); XMLWriter writer = new XMLWriter(newFileWriter("output.xml"),format); writer.write(document); writer.close();
Dom4j在指定位置插入节点:
a.得到插入位置的节点列表(list)
b.调用list.add(index,elemnent),由index决定element的插入位置
c.Element元素可以通过DocumentHelper对象得到。示例代码:
Element aaa = DocumentHelper.createElement("aaa"); aaa.setText("aaa"); List list = root.element("书").elements(); list.add(1, aaa); //更新document
同样对于上面的xml文件,解析过程如下:
import java.io.InputStream; import java.util.List; import org.dom4j.Document; import org.dom4j.DocumentException; import org.dom4j.Element; import org.dom4j.io.SAXReader; /** * dom4j解析xml文件 * 要想使用dom4j来解析,首先需要导入jar包 * @author Administrator * */ public class Test { public static void parseXML(){ try { SAXReader reader = new SAXReader(); InputStream is = Test.class.getResourceAsStream("/stus2.xml"); Document doc = reader.read(is); //得到文档对象后,要开始解析,先得到xml文件的根节点 Element root = doc.getRootElement(); //得到根节点下的所有子节点 List<Element> list = root.elements(); for (int i = 0; i < list.size(); i++) { Element element = list.get(i); String id = element.attributeValue("id"); System.out.println("id:"+id); //得到名字叫做stuname的子节点,如果有多的,得到的是第一个 //Element e = element.element("stuname"); //也可以得到指定名字的多个子节点 //List<Element> list = element.elements(""); //得到stu节点下的所有子节点(比如stuname,stuage...) List<Element> childlist = element.elements(); for (int j = 0; j < childlist.size(); j++) { Element child = childlist.get(j); String name = child.getName(); String value = child.getTextTrim(); System.out.println("节点名字:"+name+",节点的值:"+value); } System.out.println("****************************************"); } } catch (DocumentException e) { e.printStackTrace(); } } public static void main(String[] args) { Test.parseXML(); } }