XML

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 &lt; 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();
  }
}

 

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值