少女祈祷中...

1.XML简介

  • 可扩展标记语言:意义+数据
  • 标签可自行定义,具有自我描述性
  • 纯文本表示,跨系统/平台/语言
  • W3C标准(1998年,W3C发布了XML1.0,包括几乎所有的Unicode字符)
1
2
3
4
5
<Student>
<name>Tom</name>
<age>20</age>
</Student>

XML结构

  • 常规语法
    • 任何的起始标签都必须有一个结束标签
    • 简化写法,例如,<name></name>可以写为<name/>
    • 大小写敏感,如<name>和<Name>不一样
    • 每个文件都要有一个根元素
    • 标签必须按合适的顺序进行嵌套,不可错位
    • 所有的特性都必须有值,且在值的周围加上引号
    • 需要转义字符,如“<”需要用<代替
    • 注释:<!-- 注释内容 -->

XML扩展

  • DTD(Document Type Definition)
    • 定义 XML 文档的结构
    • 使用一系列合法的元素来定义文档结构
    • 可嵌套在xml文档中,或者在xml中引用
  • XML Schema(XSD,XML Schema Definition)
    • 定义 XML 文档的结构, DTD的继任者
    • 支持数据类型,可扩展,功能更完善、强大
    • 采用xml编写
  • XSL
    • 扩展样式表语言(eXtensible Stylesheet Language)
    • XSL作用于XML,等同于CSS作用于HTML
    • 内容
      • XSLT: 转换 XML 文档
      • XPath: 在 XML 文档中导航
      • XSL-FO: 格式化XML文档

XML解析

  • 树结构
    • DOM: Document Object Model 文档对象模型,擅长(小规模)读/写
  • 流结构
    • SAX: Simple API for XML 流机制解释器(推模式),擅长读
    • Stax: The Streaming API for XML 流机制解释器(拉模式),擅长读,JDK 6 引入

2.XML解析(基于DOM)

  • DOM 是 W3C 处理 XML 的标准 API
    • 直观易用
    • 其处理方式是将 XML 整个作为类似树结构的方式读入内存中以便操作及解析,方便修改
    • 解析大数据量的 XML 文件,会遇到内存泄露及程序崩溃的风险
1
2
3
4
<font>
<name>Helvetica</name>
<size>36</size>
</font>
graph TB
    Document---ele[Element]
    ele---tex[Text:whitespace]
    ele---name[Element]
    ele---tex2[Text:whitespace]
    ele---size[Element]
    ele---tex3[Text:whitespace]
    name---tex4[Text:Helvetica]
    size---tex5[Text:36]

DOM类

  • DocumentBuilder 解析类,parse方法
  • Node 节点主接口,getChildNodes返回一个NodeList
  • NodeList 节点列表,每个元素是一个Node
  • Document 文档根节点
  • Element 标签节点元素 (每一个标签都是标签节点)
  • Text节点 (包含在XML元素内的,都算Text节点)
  • Attr节点(每个属性节点)

读取:

1. 自上而下遍历(DFS):
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
//DOM解析xml文件
DocumentBuilderFactory dbf = DocumentBuilderFactory.newInstance();
DocumentBuilder db = dbf.newDocumentBuilder();
Document document = db.parse("pom.xml");
//获取所有一级子节点
NodeList usersList = document.getChildNodes();
System.out.println(usersList.getLength());

for (int i = 0; i < usersList.getLength(); i++) {
Node users = usersList.item(i);
//获取二级子节点列表
NodeList userList = users.getChildNodes();
System.out.println("==" + userList.getLength());

for (int j = 0; j < userList.getLength(); j++) {
Node user = userList.item(j);
//排除whitespace
if (user.getNodeType() == Node.ELEMENT_NODE) {
//获取三级子节点列表
NodeList metaList = user.getChildNodes();
System.out.println("====" + metaList.getLength());
//......
}
}
}
2. 根据名称进行搜索
1
2
3
4
5
6
7
8
9
10
11
12
13
14
//DOM解析xml文件
DocumentBuilderFactory dbf = DocumentBuilderFactory.newInstance();
DocumentBuilder db = dbf.newDocumentBuilder();
Document document = db.parse("pom.xml");

Element rootElement =document.getDocumentElement();
//获取所有标签名为name的节点
NodeList nodeList=rootElement.getElementsByTagName("name");
if(nodeList!=null) {
for(int i=0;i<nodeList.getLength();i++) {
Element element = (Element)nodeList.item(i);
System.out.println(element.getNodeName()+"="+element.getTextContent());
}
}

写入:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
DocumentBuilderFactory dbFactory = DocumentBuilderFactory.newInstance();
DocumentBuilder dbBuilder = dbFactory.newDocumentBuilder();
//新建Documnet根节点
Document document = dbBuilder.newDocument();
if (document != null) {
Element docx = document.createElement("document"); //均采用Doucument创建元素
Element element = document.createElement("element");
element.setAttribute("type", "paragraph");
element.setAttribute("alignment", "left"); //element新增两个属性

Element object = document.createElement("object");
object.setAttribute("type", "text");

Element text = document.createElement("text");
text.appendChild(document.createTextNode("abcdefg")); //text节点赋值
Element bold = document.createElement("bold");
bold.appendChild(document.createTextNode("true")); //bold节点赋值

object.appendChild(text);
object.appendChild(bold);
element.appendChild(object);
docx.appendChild(element);
document.appendChild(docx); //创建树状结构

TransformerFactory transformerFactory = TransformerFactory.newInstance();
Transformer transformer = transformerFactory.newTransformer();
DOMSource source = new DOMSource(document);
//定义目标文件
File file = new File("dom_result.xml");
StreamResult result = new StreamResult(file);
//将xml内容写入到文件中
transformer.transform(source, result);
}

3.XML解析(基于SAX)

Simple API for XML

  • 采用事件/流模型来解析 XML 文档,更快速、更轻量
  • 有选择的解析和访问,不像 DOM 加载整个文档,内存要求较低
  • SAX 对 XML 文档的解析为一次性读取,不创建/不存储文档对象,很难同时访问文档中的多处数据
  • 推模型。当它每发现一个节点就引发一个事件,而我们需要编写这些事件的处理程序
  • 关键类:DefaultHandler
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
public class SAXReader {
public static void main(String[] args) throws SAXException, IOException {
XMLReader parser = XMLReaderFactory.createXMLReader();
BookHandler bookHandler = new BookHandler();
parser.setContentHandler(bookHandler);
parser.parse("books.xml");
System.out.println(bookHandler.getNameList());
}
}

class BookHandler extends DefaultHandler {
private List<String> nameList;
private boolean title = false;

public List<String> getNameList() {
return nameList;
}

// xml文档加载时
public void startDocument() throws SAXException {
System.out.println("Start parsing document...");
nameList = new ArrayList<String>();
}

// 文档解析结束
public void endDocument() throws SAXException {
System.out.println("End");
}

// 访问某一个元素
public void startElement(String uri, String localName, String qName, Attributes atts) throws SAXException {
if (qName.equals("title")) {
title = true;
}
}

// 结束访问元素
public void endElement(String namespaceURI, String localName, String qName) throws SAXException {
// End of processing current element
if (title) {
title = false;
}
}

// 访问元素正文
public void characters(char[] ch, int start, int length) {
if (title) {
String bookTitle = new String(ch, start, length);
System.out.println("Book title: " + bookTitle);
nameList.add(bookTitle);
}
}
}

4.XML解析(基于Stax)

Streaming API for XML

  • 流模型中的拉模型
  • 在遍历文档时,会把感兴趣的部分从读取器中拉出,不需要引发事件,允许我们选择性地处理节点。这大大提高了灵活性,以及整体效率
  • 两套处理API
    • 基于指针的API, XMLStreamReader
    • 基于迭代器的API,XMLEventReader
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
public class StaxReader {

public static void main(String[] args) {
StaxReader.readByStream(); //基于指针遍历
StaxReader.readByEvent(); //基于迭代器遍历
}

// 流模式
public static void readByStream() {
//固定写法
String xmlFile = "books.xml";
XMLInputFactory factory = XMLInputFactory.newFactory();
XMLStreamReader streamReader = null;
try {
streamReader = factory.createXMLStreamReader(new FileReader(xmlFile));
} catch (FileNotFoundException e) {
e.printStackTrace();
} catch (XMLStreamException e) {
e.printStackTrace();
}

//基于指针遍历
try {
while (streamReader.hasNext()) {
int event = streamReader.next();
// 如果是元素的开始
if (event == XMLStreamConstants.START_ELEMENT) {
// 列出所有书籍名称
if ("title".equalsIgnoreCase(streamReader.getLocalName())) {
System.out.println("title:" + streamReader.getElementText());
}
}
}
streamReader.close();
} catch (XMLStreamException e) {
e.printStackTrace();
}
}

// 事件模式
public static void readByEvent() {
String xmlFile = "books.xml";
XMLInputFactory factory = XMLInputFactory.newInstance();
boolean titleFlag = false;
try {
// 创建基于迭代器的事件读取器对象
XMLEventReader eventReader = factory.createXMLEventReader(new FileReader(xmlFile));
// 遍历Event迭代器
while (eventReader.hasNext()) {
XMLEvent event = eventReader.nextEvent();
// 如果事件对象是元素的开始
if (event.isStartElement()) {
// 转换成开始元素事件对象
StartElement start = event.asStartElement();
// 打印元素标签的本地名称

String name = start.getName().getLocalPart();
// System.out.print(start.getName().getLocalPart());
if (name.equals("title")) {
titleFlag = true;
System.out.print("title:");
}

// 取得所有属性
Iterator attrs = start.getAttributes();
while (attrs.hasNext()) {
// 打印所有属性信息
Attribute attr = (Attribute) attrs.next();
// System.out.print(":" + attr.getName().getLocalPart() + "=" +
// attr.getValue());
}
// System.out.println();
}
// 如果是正文
if (event.isCharacters()) {
String s = event.asCharacters().getData();
if (null != s && s.trim().length() > 0 && titleFlag) {
System.out.println(s.trim());
}
}
// 如果事件对象是元素的结束
if (event.isEndElement()) {
EndElement end = event.asEndElement();
String name = end.getName().getLocalPart();
if (name.equals("title")) {
titleFlag = false;
}
}
}
eventReader.close();
} catch (FileNotFoundException e) {
e.printStackTrace();
} catch (XMLStreamException e) {
e.printStackTrace();
}
}
}

5.JSON简介

  • JavaScript Object Notation, JS 对象表示法
  • 是一种轻量级的数据交换格式
  • 类似XML,更小、更快、更易解析
  • 最早用于Javascript中,容易解析,最后推广到全语言
  • 尽管使用Javascript语法,但是独立于编程语言

JSONObject和JSONArray

Java的JSON处理

  • org.json:JSON官方推荐的解析类
    • 简单易用,通用性强
    • 复杂功能欠缺
  • GSON:Google出品
    • 基于反射,可以实现JSON对象、JSON字符串和Java对象互转
  • Jackson:号称最快的JSON处理器
    • 简单易用,社区更新和发布速度比较快

Json主要用途

  • JSON生成
  • JSON解析
  • JSON校验
  • Java Bean对象进行互解析
    • 具有一个无参的构造函数
    • 可以包括多个属性,所有属性都是private
    • 每个属性都有相应的Getter/Setter方法
    • Java Bean用于封装数据,又可称为POJO(Plain Old Java Object)

org.json

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
public static void main(String[] args) {
testJsonObject();
testJsonFile();
}

public static void testJsonObject() {
// 构造对象
Person p = new Person();
p.setName("Tom");
p.setAge(20);

// 构造JSONObject对象
JSONObject obj = new JSONObject();
obj.put("name", p.getName());
obj.put("age", p.getAge());
System.out.println("name: " + obj.getString("name"));
System.out.println("age: " + obj.getInt("age"));
}

public static void testJsonFile() {
File file = new File("books.json");
try (FileReader reader = new FileReader(file)) {
// 读取文件内容到JsonObject对象中
int fileLen = (int) file.length();
char[] chars = new char[fileLen];
reader.read(chars);
String s = String.valueOf(chars);
JSONObject jsonObject = new JSONObject(s);

// 开始解析JSONObject对象
JSONArray books = jsonObject.getJSONArray("books");
List<Book> bookList = new ArrayList<>();
for (Object book : books) {
// 获取单个JSONObject对象
JSONObject bookObject = (JSONObject) book;
Book book1 = new Book();
book1.setAuthor(bookObject.getString("author"));
book1.setYear(bookObject.getString("year"));
book1.setTitle(bookObject.getString("title"));
book1.setPrice(bookObject.getInt("price"));
book1.setCategory(bookObject.getString("category"));
bookList.add(book1);
}

for (Book book : bookList) {
System.out.println(book.getAuthor() + ", " + book.getTitle());
}
} catch (Exception e) {
e.printStackTrace();
}
}

GSON

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
public static void main(String[] args) {
testJsonObject();
testJsonFile();
}

public static void testJsonObject() {
// 构造对象
Person p = new Person();
p.setName("Tom");
p.setAge(20);

// 从Java对象到JSON字符串
Gson gson = new Gson();
String s = gson.toJson(p);
System.out.println(s); // {"name":"Tom","age":20}

// 从JSON字符串到Java对象
Person p2 = gson.fromJson(s, Person.class);
System.out.println(p2.getName()); // Tom
System.out.println(p2.getAge()); // 20

// 调用GSON的JsonObject
JsonObject json = gson.toJsonTree(p).getAsJsonObject(); // 将整个json解析为一颗树
System.out.println(json.get("name")); // "Tom"
System.out.println(json.get("age")); // 20
}

public static void testJsonFile() {
Gson gson = new Gson();
File file = new File("books2.json");

try (FileReader reader = new FileReader(file)) {
List<Book> books = gson.fromJson(reader, new TypeToken<List<Book>>() {
}.getType());

for (Book book : books) {
System.out.println(book.getAuthor() + ", " + book.getTitle());
}
} catch (Exception e) {
e.printStackTrace();
}
}

Jackson

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
public static void main(String[] args) throws Exception {
testJsonObject();
testJsonFile();
}

static void testJsonObject() throws IOException {
ObjectMapper om = new ObjectMapper();

//构造对象
Person p = new Person();
p.setName("Tom");
p.setAge(20);

//将对象解析为json字符串
String jsonStr = om.writeValueAsString(p);
System.out.println(jsonStr);

//从json字符串重构对象
Person p2 = om.readValue(jsonStr, Person.class);
System.out.println(p2.getName());
System.out.println(p2.getAge());

//从json字符串重构为JsonNode对象
JsonNode node = om.readTree(jsonStr);
System.out.println(node.get("name").asText());
System.out.println(node.get("age").asText());
}

static void testJsonFile() throws IOException {
ObjectMapper om = new ObjectMapper();

//从json文件中加载,并重构为java对象
File json2 = new File("books2.json");
List<Book> books = om.readValue(json2, new TypeReference<List<Book>>(){});
for (Book book : books) {
System.out.println(book.getAuthor());
System.out.println(book.getTitle());
}
}

JSON vs XML

  • 都是数据交换格式,可读性强,可扩展性高
  • 大部分的情况下,JSON更具优势(编码简单,转换方便)
  • JSON字符长度一般小于XML,传输效率更高
  • XML更加注重标签和顺序
  • JSON会丢失信息