-
XML 指可扩展标记语言(EXtensible Markup Language)
-
XML 是一种标记语言,很类似 HTML
-
XML 的设计宗旨是传输数据,而非显示数据
-
XML 标签没有被预定义。您需要自行定义标签。
-
XML 被设计为具有自我描述性。
-
XML 是 W3C 的推荐标准
2、XML组成
2.1、标签
-
标签是由尖括号 包围的关键词,比如
<book/>
-
标签通常是成对出现 的,比如
<b></b>
-
标签对中的第一个标签是开始标签 ,第二个标签是结束标签 ,开始和结束标签也被称为开放标签 和闭合标签
-
空标签 由 一些标签没有内容,可以用一个标签来表示,比如setting标签
<settings> <setting name="useGeneratedKeys" value="true"/> <setting name="mapUnderscoreToCamelCase" value="true"/> <setting name="logImpl" value="LOG4J"/> </settings>
2.2、属性
标签可以拥有属性 。属性提供了有关 HTML 元素的更多的信息 。
属性总是以名称/值对的形式出现,比如:name="value" 。
属性总是在 HTML 元素的开始标签 中规定。
实例如下
<a href="http://www.w3school.com.cn">This is a link</a>
2.3、文本内容
在开始标签与结束标签中可以存放文本内容
2.4、XML 元素
xml元素指的是从(且包括)开始标签直到(且包括)结束标签的部分。
2.5、XML 文档形成一种树结构
下面的 XML 文档表示书店中有的书
<bookstore>
<book category="COOKING">
<title lang="en">Everyday Italian</title>
<author>Giada De Laurentiis</author>
<year>2005</year>
<price>30.00</price>
</book>
<book category="CHILDREN">
<title lang="en">Harry Potter</title>
<author>J K. Rowling</author>
<year>2005</year>
<price>29.99</price>
</book>
<book category="WEB">
<title lang="en">Learning XML</title>
<author>Erik T. Ray</author>
<year>2003</year>
<price>39.95</price>
</book>
</bookstore>
上述XML文档可以表示成一个树形结构
3、xml基础语法
-
XML 文档必须包含根元素 。该元素是所有其他元素的父元素。
-
所有 XML 元素都须有关闭标签。
-
XML 标签对大小写敏感
-
XML 的属性值须加引号
-
XML 必须正确地嵌套
-
实体引用
在 XML 中,一些字符拥有特殊的意义。
如果你把字符 "<" 放在 XML 元素中,会发生错误,这是因为解析器会把它当作新元素的开始。
这样会产生 XML 错误
<message>if salary < 1000 then</message>
为了避免这个错误,请用实体引用 来代替 "<" 字符:
<message>if salary < 1000 then</message>
在 XML 中,有 5 个预定义的实体引用:
< 小于 > 大于 & 与 ' 单引号 " 引号 -
XML 中的注释
在 XML 中编写注释的语法与 HTML 的语法很相似:
<!-- This is a comment -->
-
在 XML 中,空格会被保留
HTML 会把多个连续的空格字符裁减(合并)为一个:
HTML: Hello my name is David. 输出: Hello my name is David.
在 XML 中,文档中的空格不会被删节。
-
xml文档声明
一个 XML 文档实例
<?xml version="1.0" encoding="UTF-8" standalone="yes" ?>
<note>
<to>George</to>
<from>John</from>
<heading>Reminder</heading>
<body>Don't forget the meeting!</body>
</note>
第一行:
<?xml version="1.0" encoding="UTF-8" standalone="no"?>
语法要求<,?,xml之间不能有空格, ?>之间不能有空格,standalone="no"?两者之间可以有一个或多个空格。
encoding=”utf-8”:那么解析器读到该属性,那么会以utf-8解码,如果不写呢?XML解析器通过寻找XML文档开始处的字节序列,能够自动检测出文档中的Unicode编码是UTF-8还是UTF-16.也就是说encoding属性的默认值是Unicode编码,如果文档是以UTF-8/UTF-16编码那么可以不设置该属性.
standalone属性用于说明文档是否独立(该文档没有依赖外面的任何文件而可以单独存在(例如依赖dtd文件) 所以值是yes,)。独立的文档是yes, 依赖外部文件的文档是no。standalone属性位于encoding属性之后。
4、XML文档解析
XML的解析方式分为两种:1、DOM解析;2、SAX解析
4.1、DOM解析
**DOM的全称是Document Object Model,也即文档对象模型。在应用程序中,基于DOM的XML分析器将一个XML文档转换成一个对象模型的集合(通常称DOM树),应用程序正是通过对这个对象模型的操作,来实现对XML文档数据的操作。通过DOM接口,应用程序可以在任何时候访问XML文档中的任何一部分数据,因此,这种利用DOM接口的机制也被称作随机访问机制。**
**DOM接口提供了一种通过分层对象模型来访问XML文档信息的方式,这些分层对象模型依据XML的文档结构形成了一棵节点树。无论XML文档中所描述的是什么类型的信息,即便是制表数据、项目列表或一个文档,利用DOM所生成的模型都是节点树的形式。也就是说,DOM强制使用树模型来访问XML文档中的信息。由于XML本质上就是一种分层结构,所以这种描述方法是相当有效的。**
DOM树所提供的随机访问方式给应用程序的开发带来了很大的灵活性,它可以任意地控制整个XML文档中的内容。然而,由于DOM分析器把整个XML文档转化成DOM树放在了内存中,因此,当文档比较大或者结构比较复杂时,对内存的需求就比较高。而且,对于结构复杂的树的遍历也是一项耗时的操作。所以,DOM分析器对机器性能的要求比较高,实现效率不十分理想。不过,由于DOM分析器所采用的树结构的思想与XML文档的结构相吻合,同时鉴于随机访问所带来的方便,因此,DOM分析器还是有很广泛的使用价值的。
优点:
1、形成了树结构,有助于更好的理解、掌握,且代码容易编写。
2、解析过程中,树结构保存在内存中,方便修改。
缺点:
1、由于文件是一次性读取,所以对内存的耗费比较大。
2、如果XML文件比较大,容易影响解析性能且可能会造成内存溢出。
xml实例
<?xml version="1.0" encoding="UTF-8"?>
<bookstore>
<book id="1">
<name>冰与火之歌</name>
<author>乔治马丁</author>
<year>2014</year>
<price>89</price>
</book>
<book id="2">
<name>安徒生童话</name>
<year>2004</year>
<price>77</price>
<language>English</language>
</book>
</bookstore>
public class DOMTest {
public static void main(String[] args) {
//创建一个DocumentBuilderFactory的对象
DocumentBuilderFactory dbf = DocumentBuilderFactory.newInstance();
//创建一个DocumentBuilder的对象
try {
//创建DocumentBuilder对象
DocumentBuilder db = dbf.newDocumentBuilder();
//通过DocumentBuilder对象的parser方法加载books.xml文件到当前项目下
Document document = db.parse("books.xml");
//获取所有book节点的集合
NodeList bookList = document.getElementsByTagName("book");
//通过nodelist的getLength()方法可以获取bookList的长度
System.out.println("一共有" + bookList.getLength() + "本书");
//遍历每一个book节点
for (int i = 0; i < bookList.getLength(); i++) {
System.out.println("=================下面开始遍历第" + (i + 1) + "本书的内容=================");
//通过 item(i)方法 获取一个book节点,nodelist的索引值从0开始
Node book = bookList.item(i);
//获取book节点的所有属性集合
NamedNodeMap attrs = book.getAttributes();
System.out.println("第 " + (i + 1) + "本书共有" + attrs.getLength() + "个属性");
//遍历book的属性
for (int j = 0; j < attrs.getLength(); j++) {
//通过item(index)方法获取book节点的某一个属性
Node attr = attrs.item(j);
//获取属性名
System.out.print("属性名:" + attr.getNodeName());
//获取属性值
System.out.println("--属性值" + attr.getNodeValue());
}
//解析book节点的子节点
NodeList childNodes = book.getChildNodes();
//遍历childNodes获取每个节点的节点名和节点值
System.out.println("第" + (i+1) + "本书共有" +
childNodes.getLength() + "个子节点");
for (int k = 0; k < childNodes.getLength(); k++) {
//区分出text类型的node以及element类型的node
if (childNodes.item(k).getNodeType() == Node.ELEMENT_NODE) {
//获取了element类型节点的节点名
System.out.print("第" + (k + 1) + "个节点的节点名:"
+ childNodes.item(k).getNodeName());
//获取了element类型节点的节点值
System.out.println("--节点值是:" + childNodes.item(k).getFirstChild().getNodeValue());
//System.out.println("--节点值是:" + childNodes.item(k).getTextContent());
}
}
System.out.println("======================结束遍历第" + (i + 1) + "本书的内容=================");
}
} catch (ParserConfigurationException e) {
e.printStackTrace();
} catch (SAXException e) {
e.printStackTrace();
} catch (IOException e) {
e.printStackTrace();
}
}
}
上述代码把XML解析成Document ,对XML元素的访问太过麻烦,还有一种通过XPaht方式的访问方式,在Mybatis中也是采取这种方式
实例如下
<?xml version="1.0" encoding="UTF-8" ?>
<users>
<user id = "1">
<name>张三</name>
<createTime>2018-06-06 00:00:00</createTime>
<passward>admin</passward>
<phone>180000000</phone>
<nickName>阿毛</nickName>
</user>
<user id = "2">
<name>李四</name>
<createTime>2018-06-06 00:00:00</createTime>
<passward>admin</passward>
<phone>180000001</phone>
<nickName>明明</nickName>
</user>
</users>
xml对应的java类
package com.blog4java.mybatis.xpath;
import lombok.Data;
import java.util.Date;
@Data
public class UserEntity {
private Long id;
private String name;
private Date createTime;
private String password;
private String phone;
private String nickName;
}
java解析代码
package com.blog4java.mybatis.xpath;
import com.alibaba.fastjson.JSON;
import org.apache.commons.beanutils.BeanUtils;
import org.apache.commons.beanutils.ConvertUtils;
import org.apache.commons.beanutils.converters.DateConverter;
import org.apache.ibatis.builder.BuilderException;
import org.apache.ibatis.io.Resources;
import org.junit.Test;
import org.w3c.dom.Document;
import org.w3c.dom.NodeList;
import javax.xml.parsers.DocumentBuilder;
import javax.xml.parsers.DocumentBuilderFactory;
import javax.xml.xpath.XPath;
import javax.xml.xpath.XPathConstants;
import javax.xml.xpath.XPathFactory;
import java.io.InputStream;
import java.lang.reflect.InvocationTargetException;
import java.util.ArrayList;
import java.util.Date;
import java.util.List;
public class XPathExample {
@Test
public void testXPathParser() {
try {
// 创建DocumentBuilderFactory实例 Jdk内部的类
DocumentBuilderFactory factory = DocumentBuilderFactory.newInstance();
// 创建DocumentBuilder实例
DocumentBuilder builder = factory.newDocumentBuilder();
InputStream inputSource = Resources.getResourceAsStream("users.xml");
Document doc = builder.parse(inputSource);
// 获取XPath实例 Jdk内部的类
XPath xpath = XPathFactory.newInstance().newXPath();
// 执行XPath表达式,获取节点信息
NodeList nodeList = (NodeList)xpath.evaluate("/users/*", doc, XPathConstants.NODESET);
List<UserEntity> userList = new ArrayList<>();
for(int i=1; i < nodeList.getLength() + 1; i++) {
String path = "/users/user["+i+"]";
String id = (String)xpath.evaluate(path + "/@id", doc, XPathConstants.STRING);
String name = (String)xpath.evaluate(path + "/name", doc, XPathConstants.STRING);
String createTime = (String)xpath.evaluate(path + "/createTime", doc, XPathConstants.STRING);
String passward = (String)xpath.evaluate(path + "/passward", doc, XPathConstants.STRING);
String phone = (String)xpath.evaluate(path + "/phone", doc, XPathConstants.STRING);
String nickName = (String)xpath.evaluate(path + "/nickName", doc, XPathConstants.STRING);
// 调用buildUserEntity()方法,构建UserEntity对象
UserEntity userEntity = buildUserEntity(id,name, createTime, passward, phone, nickName);
userList.add(userEntity);
}
System.out.println(JSON.toJSONString(userList));
} catch (Exception e) {
throw new BuilderException("Error creating document instance. Cause: " + e, e);
}
}
private UserEntity buildUserEntity(String id,String name,
String createTime, String passward,
String phone, String nickName)
throws IllegalAccessException, InvocationTargetException {
UserEntity userEntity = new UserEntity();
DateConverter dateConverter = new DateConverter(null);
dateConverter.setPattern("yyyy-MM-dd HH:mm:ss");
ConvertUtils.register(dateConverter,Date.class);
BeanUtils.setProperty(userEntity,"id",id);
BeanUtils.setProperty(userEntity,"name",name);
BeanUtils.setProperty(userEntity,"createTime",createTime);
BeanUtils.setProperty(userEntity,"passward",passward);
BeanUtils.setProperty(userEntity,"phone",phone);
BeanUtils.setProperty(userEntity,"nickName",nickName);
return userEntity;
}
}