XML小结
一、XML概述
英文全称为Extensible Markup Language,翻译过来为可扩展标记语言。XML技术是W3C组织发布的,目前遵循的是W3C组织于2000发布的XML1.0规范。XML就是为了解决这样的需求而产生数据存储格式。
在XML语言中,它允许用户自定义标签。每一个标签用于描述一段数据;一个标签可以分为开始标签和结束标签,在开始标签和结束标签之间又可以嵌套其它标签,利用标签间的嵌套关系来保存数据之间的上下级关系;由于xml实质上是一段字符串,计算机可以十分方便的对他进行操作,开发人员也可以方便的阅读,因此可以说这是一种对人、对计算机都友好的数据存储格式,所以XML迅速普及,成为了一种非常常见的数据存储格式,在许多应用场景中得到应用。
XML本质上是一段字符串,具有跨平台性的特性,因此XML常被用来在不同系统之间进行数据交换。XML可以在保存数据的同时保存数据之间的关系。利用这一特点,它还经常用作应用程序配置文件来使用。
XML校验:浏览器除了内置HTML解析其外还内置了XML解析器,因此我们可以使用浏览器对XML进行校验。
二、XML语法
一个XML文件分为如下几部分内容:1.文档声明 2.元素 3.属性 4.注释 5.CDATA区 6.特殊字符 7.处理指令(processing instruction)
文档声明
XML的文档声明是用来声明文档基本属性的,XML解析器将根据文档声明决定如何正确解析一个XML。通常来说一个XML必须包含且只包含一个文档声明;文档声明必须处在XML的第一行,前面不能有其他内容;如果一个XML不包含文档声明则称这样的XML为格式不良好的XML;在许多时候即使不包含文档声明,XML也可以被正常使用,但是这是不符合标准的,存在风险,因此强烈推荐大家在书写XML时写上文档声明。
最简单写法: <?xml version="1.0" ?> version 代表当前xml所遵循的xml标准;在第二个问号之前应该有一个空格。注意:问号、引号、空格都必须为英文半角
用encoding属性说明文档的字符编码:<?xml version="1.0" encoding="GB2312" ?> encoding告知解析器使用何种编码解析当前xml;encoding默认值为ISO8859-1
用standalone属性说明文档是否独立:<?xml version="1.0" encoding="GB2312" standalone="yes" ?> standalone表示当前xml文档是否是一个独立文档,当为yes时表示是一个独立文档,当为no时表示当前文档需要其他文档支持。
XML元素
一个XML标签就是一个XML元素。 一个XML标签分为开始标签和结束标签,在开始标签和结束标签之间的文本被称为标签体。 包含标签体:<a>www.itcast.cn</a>; 如果一个不包含标签体也不包含其他元素,那么可以将开始标签和结束标签合并,这样的标签称为自闭标签 不含标签体及其他元素:<a></a>可以简写为自闭标签:<a/>
一个标签中也可以嵌套若干子标签。但所有标签必须合理的嵌套,绝对不允许交叉嵌套 ,
例如: <a>welcome to www.it315.org<b/></a> <a>welcome to www.it315<b/>.org</a>
格式良好的XML文档必须有且仅有一个根标签,其它标签都是这个根标签的子孙标签。
对于XML标签中出现的所有空格和换行,XML解析程序都会当作标签内容进行处理。例如:下面两段内容的意义是不一样的。
<网址>www.itcast.cn</网址>
<网址>
www.itcast.cn
</网址>
由于在XML中,空格和换行都作为原始内容被处理,所以,在编写XML文件时,使用换行和缩进等方式来让原文件中的内容清晰可读的“良好”书写习惯可能要被迫改变。
一个XML元素可以包含字母、数字以及其它一些可见字符,但必须遵守下面的一些规范:区分大小写,例如,<P>和<p>是两个不同的标记;不能以数字或标点符号或"_"开头;不能以xml(或XML、或Xml 等)开头;不能包含空格;名称中间不能包含冒号(:)。
XML属性
一个标签可以有多个属性,每个属性都有它自己的名称和取值,例如:<china capital="beijing"/>
属性值一定要用双引号(")或单引号(')引起来,<china capital='beijing'/>
定义属性名必须遵循与元素相同的命名规范
XML注释
Xml文件中的注释采用:“<!--注释-->” 格式。
注释不能出现在文档声明之前(因为XML要求文档声明必须在第一行,之前不能有其他内容);注释不能嵌套
CDATA区
当XML中一段内容不希望被解析器解析时可以使用CDATA区将其包住,当解析器遇到CDATA区时会将其内容当作文本对待,不会进行解析。语法:<![CDATA[ 内容 ]]>
XML处理指令
处理指令,简称PI (processing instruction),处理指令用来指挥解析引擎如何解析XML文档内容。例如,在XML文档中可以使用xml-stylesheet指令,通知XML解析引擎,应用css文件显示xml文档内容。 <?xml-stylesheet type="text/css" href="1.css"?> 处理指令必须以“<?”作为开头,以“?>”作为结尾,XML文档声明语句就是最常见的一种处理指令。
三、XML约束
在xml技术里,可以编写一个文档来约束一个xml文档的写法,这称之为XML约束。作用:约束xml文档的写法、对xml进行校验。常见的XML约束技术:XML DTD 、
XML Schema。
DTD约束
DTD(Document Type Definition),全称为文档类型定义。
例:文件清单:book.dtd
1 <!ELEMENT 书架 (书+)> 2 <!ELEMENT 书 (书名,作者,售价)> 3 <!ELEMENT 书名 (#PCDATA)> 4 <!ELEMENT 作者 (#PCDATA)> 5 <!ELEMENT 售价 (#PCDATA)>
文件清单:book.xml
1 <?xml version="1.0" encoding="gb2312"?> 2 <!DOCTYPE 书架 SYSTEM "book.dtd"> 3 <书架> 4 <书> 5 <书名>Java就业培训教程</书名> 6 <作者>张孝祥</作者> 7 <售价>39.00元</售价> 8 </书> 9 <书> 10 <书名>JavaScript网页开发</书名> 11 <作者>张孝祥</作者> 12 <售价>28.00元</售价> 13 </书> 14 </书架>
编程校验XML文档正确性:默认的情况下IE浏览器内置的XML解析器的 约束校验器是被关闭了的。所以我们需要使用JavaScript手动创建解析器对象,打开约束校验功能,对XML进行约束校验。1.创建xml文档解析器对象 var xmldoc = new ActiveXObject("Microsoft.XMLDOM"); 2.开启xml校验 xmldoc.validateOnParse = "true";3.装载xml文档 xmldoc.load("book.xml"); 4.获取错误信息 xmldoc.parseError.reason; xmldoc.parseError.line;
引入DTD约束的两种方式:DTD的约束可以定义在XML文件内部,如果DTD被定义在了XML内部则XML文档声明中standalone="yes";DTD的约束也可以定义在一个独立的 后缀为.dtd的文件中再由xml文件引入,此时引入此dtd的xml文档声明中standalone="no"。
XML文件使用 DOCTYPE 声明语句来指明它所遵循的DTD文件,DOCTYPE声明语句有两种形式:
当引用的文件在本地时,采用如下方式: <!DOCTYPE 文档根结点 SYSTEM "DTD文件的URL">
例如:<!DOCTYPE 书架 SYSTEM “book.dtd”>
当引用的文件是一个公共的文件时,采用如下方式: <!DOCTYPE 文档根结点 PUBLIC "DTD名称" "DTD文件的URL">
例如:<!DOCTYPE web-app PUBLIC "-//Sun Microsystems, Inc.//DTD Web Application 2.3//EN" "http://java.sun.com/dtd/web-app_2_3.dtd">
四、DTD语法
元素定义
在DTD文档中使用ELEMENT声明一个XML元素,语法格式如下所示: <!ELEMENT 元素名称 元素约束>
元素约束可以是元素内容、或存放类型
如为元素内容:则需要使用()括起来,如 <!ELEMENT 书架 (书名,作者,售价)> <!ELEMENT 书名 (#PCDATA)>
如为存放类型,则直接书写,DTD规范定义了如下几种类型: EMPTY:用于定义空元素,例如<br/> <hr/> ANY:表示元素内容为任意类型。
元素内容中可以使用如下方式,描述内容的组成关系,用逗号分隔,表示内容的出现顺序必须与声明时一致,例如<!ELEMENT MYFILE (TITLE,AUTHOR,EMAIL)>; 用|分隔,表示任选其一,即多个只能出现一个,例如<!ELEMENT MYFILE (TITLE|AUTHOR|EMAIL)>
在元素内容中也可以使用+、*、?等符号表示元素出现的次数:1. +: 一次或多次 (书+);2.?: 0次或一次 (书?);3.*: 0次或多次 (书*)
属性定义
dtd文档中的标签属性需通过ATTLIST为其设置属性
语法格式:
<!ATTLIST 元素名 属性名1 属性类型 属性约束 属性名2 属性类型 属性约束 ……>
属性声明举例:
<!ATTLIST 商品 类别 CDATA #REQUIRED 颜色 CDATA #IMPLIED >
对应XML文件:
<商品 类别="服装" 颜色="黄色">…</商品>
<商品 类别="服装">…</商品>
属性类型: CDATA:表示属性的值是一个普通字符串; ENUMERATED : 属性的值是一个枚举列表中的值; ID: 表明属性的值必须在整个文档中都是唯一的,如果有重复的id则校验不通过,ID 属性的值只能由字母,下划线开始,不能使用数字,不能出现空白字符
属性约束: #REQUIRED:必须设置该属性; #IMPLIED:可以设置也可以不设置; #FIXED:说明该属性的取值固定为一个值,在 XML 文件中不能为该属性设置其它值。使用该元素时无需为其分配该属性,XML处理器会自动为给属性增加固定值;直接使用默认值:在 XML 中可以设置该值也可以不设置该属性值。若没设置则使用默认值。
举例:
<!ATTLIST 页面作者
姓名 CDATA #IMPLIED
年龄 CDATA #IMPLIED
联系信息 CDATA #REQUIRED
网站职务 CDATA #FIXED "页面作者"
个人爱好 CDATA "上网"
>
实体定义
<!ENTITY >,就是对一大段内容的引用,可以简化代码的复用
引用实体:在xml中引用的实体叫做引用实体 <!ENTITY 实体名称 “实体内容” > &实体名称;
举例: <!ENTITY copyright “I am a programmer"> …… ©right;
参数实体:在dtd中引用的实体叫做参数实体 <!ENTITY % 实体名称 "实体内容"> %实体名称;
举例1: <!ENTITY % TAG_NAMES "姓名 | EMAIL | 电话 | 地址">
<!ELEMENT 个人信息 (%TAG_NAMES; | 生日)>
<!ELEMENT 客户信息 (%TAG_NAMES; | 公司名)>
举例2: <!ENTITY % common.attributes " id ID #IMPLIED account CDATA #REQUIRED " >
... <!ATTLIST purchaseOrder %common.attributes;>
<!ATTLIST item %common.attributes;>
五、XML编程
XML的两种解析方式:
dom解析:将整个XML使用类似树的结构保存在内存中,再对其进行操作。是 W3C 组织推荐的处理 XML 的一种方式。需要等到XML完全加载进内存才可以进行操作,耗费内存,当解析超大的XML时慎用。可以方便的对xml进行增删该查操作
sax解析:逐行扫描XML文档,当遇到标签时触发解析处理器,采用事件处理的方式解析xml,(Simple API for XML) 不是官方标准,但它是 XML 社区事实上的标准,几乎所有的 XML 解析器都支持它。在读取文档的同时即可对xml进行处理,不必等到文档加载结束,相对快捷。不需要加载进内存,因此不存在占用内存的问题,可以解析超大XML,只能用来读取XML中数据,无法进行增删改
使用JAXP进行DOM解析
1.调用 DocumentBuilderFactory.newInstance() 方法得到创建 DOM 解析器的工厂。
DocumentBuilderFactory builderFactory = DocumentBuilderFactory.newInstance();
2.调用工厂对象的 newDocumentBuilder方法得到 DOM 解析器对象。
DocumentBuilder builder = builderFactory.newDocumentBuilder();
3.调用 DOM 解析器对象的 parse() 方法解析 XML 文档,得到代表整个文档的 Document 对象,进行可以利用DOM特性对整个XML文档进行操作了。
Document doc = builder.parse(new File("book.xml"));
DOM模型(document object model):DOM解析器在解析XML文档时,会把文档中的所有元素,按照其出现的层次关系,解析成一个个Node对象(节点),并以树的结构组织起来,存储到内存中。
JAXP中的文档对象:1.Document:文档;2.Element:元素; 3.Attr:属性; 4.CharacterData:标签体
Node对象:1.Node是一个接口,代表文档树中的单个节点,其他文档类都是Node接口的实现;2.Node接口上提供了获取父节点、获取子节点的方法,由此可以遍历文档树;3.Node接口定义了增删改查节点方法由此可以修改文档树。
参看API:
1 Node getFirstChild() 2 此节点的第一个子节点。 3 Node getLastChild() 4 此节点的最后一个节点。 getAttributes() 5 包含此节点的属性的 NamedNodeMap(如果它是 Element);否则为 null。 6 Node appendChild(Node newChild) 7 将节点 newChild 添加到此节点的子节点列表的末尾。 8 NodeList getChildNodes() 9 包含此节点的所有子节点的 NodeList。 10 getAttributes() 11 包含此节点的属性的 NamedNodeMap(如果它是 Element);否则为 null。 12 Node removeChild(Node oldChild) 13 从子节点列表中移除 oldChild 所指示的子节点,并将其返回。 14 Node replaceChild(Node newChild, Node oldChild) 15 将子节点列表中的子节点 oldChild 替换为 newChild,并返回 oldChild 节点。 16 void setTextContent(String textContent) 17 此属性返回此节点及其后代的文本内容。
对文档树的增删该查只是对内存中的对象进行的操作,如果希望将修改对xml文件起作用,就需要进行XML文档更新,javax.xml.transform包中的Transformer类用于把代表XML文件的Document对象转换为某种格式后进行输出
1.获取Transformer工厂
TransformerFactory transformerFactory = TransformerFactory.newInstance();
2.获取Transfomer对象
Transformer transformer = transformerFactory.newTransformer();
3.创建代表输入和输出的Source和Result对象
Source source = new DOMSource(doc);
Result result = new StreamResult(new FIle("book.xml"));
4.使用Transformer将 XMLSource 转换为 Result
transformer.transform(source , Result);
SAX方式解析XML文档
DOM4J解析XML文档
1.创建解析器:
SAXReader reader = new SAXReader();
2.利用解析器读入xml文档:
Document document = reader.read(new File("input.xml"));
3.获取文档的根节点:
Element root = document.getRootElement();
DOM4j节点操作:
1.取得某个节点的子节点. Element element =ele.element(“书名"); List elementList =ele.elements(“书名"); List elementList =ele.elements();
2.获取节点的名字 node.getName();
3.设置节点的名字 node.setName(String newName);
4.取得节点的文字(标签体) String text=node.getText();
5.设置节点的文字(标签体) node.setText("aaa");
6.添加子节点. ele.add(Element e);ele.addElement("age");
7.删除子节点节点. parentElm.remove(childElm);
8获取节点类型 node.getNodeType() ;
9.获取父节点 node.getParent();
10.取得某节点对象的某属性
Attribute attr= ele.attribute("aaa");
Attribute attr= ele.attribute(0);
List list = ele.attributes();
String value = ele.attributeValue("aaa");
Iterator it = ele.attributeIterator();
11.设置某节点的属性 ele.add(Attribute attr); ele.addAttribute(name, value); ele.setAttributes(List attrs);
12.删除某属性 ele.remove(attribute);
13.在指定位置插入节点:1.得到插入位置的节点列表(list);2.调用list.add(index,elemnent),由index决定element的插入位置。Element元素可以通过DocumentHelper对象得到。
示例代码:
Element aaa = DocumentHelper.createElement("aaa");
aaa.setText("aaa");
List list = root.element("书").elements();
list.add(1, aaa);
DOM4j属性:
1.取得属性的名、值 String name = attribute.getName(); String value = attribute.getValue();
2.设置某属性的名、值 attribute.setName(); attribute.setValue();
DOM4j字符串和XML的转换:
1.将字符串转化为XML
String text = "<members> <member>sitinspring</member></members>";
Document document = DocumentHelper.parseText(text);
2.将文档或节点的XML转化为字符串.
String xmlStr = node.asXML();
DOM4j将文档写入XML文件
方式一:调用Node提供的write(Writer writer) 方法,使用默认方式将节点输出到流中:node.write(new FileWriter("book.xml"));
乱码问题:Dom4j在将文档载入内存时使用的是文档声明中encoding属性声明的编码集进行编码,如果在此时使用的writer的内部编码集与最初载入内存时使用的编码集不同则会出现乱码问题。FileWriter默认使用操作系统本地码表即gb2312编码,并且无法更改。此时可以使用OutputStreamWriter(FileOutputStream("filePath"),"utf-8");的方式自己封装一个指定码表的Writer使用,从而解决乱码问题。
方式二 : 利用XMLWriter写出Node: XMLWriter writer = new XMLWriter(new FileWriter("output.xml")); writer.write(node); writer.close();
注意:使用这种方式输出时,XMLWriter首先会将内存中的docuemnt翻译成UTF-8格式的document,在进行输出,这时有可能出现乱码问题。可以使用OutputFormat 指定XMLWriter转换的编码为其他编码。
OutputFormat format = OutputFormat.createPrettyPrint();
format.setEncoding("GBK");
XMLWriter writer = new XMLWriter(newFileWriter("output.xml"),format);
Writer使用的编码集与文档载入内存时使用的编码集不同导致乱码,使用字节流或自己封装指定编码的字符流即可