Java学习——Java 之 XML与JSON的用法详解
文章目录
一、XML
概念:可扩展标记语言(eXtensible Markup Language)
特性:
- xml具有平台无关性, 是一门独立的标记语言.
- xml具有自我描述性
记:
XML文件是保存XML数据的一种方式 。
XML数据也可以以其他的方式存在(如在内存中构建XML数据)。
不要将XML语言狭隘的理解成XML文件。
1. XML的简要语法格式
- XML文档声明
<?xml version="1.0" encoding="UTF-8"?>
- 标记 ( 元素 / 标签 / 节点)
XML文档,由一个个的标记组成.。
语法:
开始标记(开放标记): <标记名称>
结束标记(闭合标记): </标记名称>
标记名称: 自定义名称,必须遵循以下命名规则:
- 1.名称可以含字母、数字以及其他的字符
- 2.名称不能以数字或者标点符号开始
- 3.名称不能以字符 “xml”(或者 XML、Xml)开始
- 4.名称不能包含空格,不能包含冒号(:)
- 5.名称区分大小写 标记内容: 开始标记与结束标记之间 ,是标记的内容.
例如 ,我们通过标记, 描述一个人名: <name>李四</name>
- 一个XML文档中, 必须有且且仅允许有一个根标记.
示例:
<names>
<name>张三</name>
<name>李四</name>
</names>
- 标记可以嵌套, 但是不允许交叉.
示例:
<person>
<name>李四</name>
<age>18</age>
</person>
- 标记的层级称呼 (子标记, 父标记 , 兄弟标记, 后代标记 ,祖先标记)
例如:
<persons>
<person>
<name>李四</name>
<length>180cm</length>
</person>
<person>
<name>李四</name>
<length>200cm</length>
</person>
</persons>
name是person的子标记,也是person的后代标记
,name是persons的后代标记;
name是length的兄弟标记,person是name的父标记,persons是name的祖先标记.
-
标记名称 允许重复
-
标记除了开始和结束 , 还有属性. 标记中的属性, 在标记开始时 描述, 由属性名和属性值 组成.
格式:在开始标记中, 描述属性. 可以包含0-n个属性, 每一个属性是一个键值对。
属性名不允许重复 , 键与值之间使用等号连接, 多个属性之间使用空格分割, 属性值必须被引号引住.
示例:
<persons>
<person id="10001" groupid="1">
<name>李四</name>
<age>18</age>
</person>
<person id="10002" groupid="1">
<name>李四</name>
<age>20</age>
</person>
</persons>
- 注释注释不能写在文档文档声明前,注释不能嵌套注释
格式:
注释开始: <!--
注释结束: -->
2. XML的解析过程
主要用到两个对象:文档对象 Document,元素对象 Element
示例 1:
添加 Demo1.xml 文件至代码的src文件下:
<?xml version="1.0" encoding="UTF-8"?>
<books>
<book id="1001">
<name>金苹果</name>
<info>苹果是真金的,所以很多人想要</info>
</book>
<book id="1002">
<name>红苹果</name>
<info>苹果是红彤彤的,所以满大街卖</info>
</book>
</books>
解析:
import org.dom4j.Document;
import org.dom4j.DocumentException;
import org.dom4j.Element;
import org.dom4j.Node;
import org.dom4j.io.SAXReader;
import java.io.FileInputStream;
import java.io.IOException;
import java.util.List;
/**
* 解析本地xml文件
*/
public class Demo1 {
public static void main(String[] args) throws IOException, DocumentException {
//获取输入流
FileInputStream fis = new FileInputStream("src/Demo1.xml");
//创建XML读取对象
SAXReader saxReader = new SAXReader();
//对对象进行获取读取
Document doc = saxReader.read(fis);
//通过获取到的文档对象,进行解析操作——获取xml中的根元素root
Element root = doc.getRootElement();
//进一步解析xml文档中的内容
System.out.println("根元素名称:" + root.getName());
//获取根元素下的所有元素
List<Element> element = root.elements();
for (int i = 0;i < element.size();i++) {
System.out.println("----------------------------");
Element book = element.get(i); //输出元素book下的所有便签的信息
System.out.println("id:" + book.attributeValue("id"));
System.out.println("name;" + book.elementText("name"));
System.out.println("info:" + book.elementText("info"));
}
fis.close(); //关闭文件输入流
}
}
输出结果:
示例 2 :
import org.dom4j.Document;
import org.dom4j.DocumentException;
import org.dom4j.Element;
import org.dom4j.Node;
import org.dom4j.io.SAXReader;
import java.io.IOException;
import java.io.InputStream;
import java.net.URL;
import java.net.URLConnection;
import java.util.Scanner;
/**
* 解析网络文件案例,从某API网站获取手机信息
*/
public class Demo2 {
public static void main(String[] args) throws IOException, DocumentException {
Scanner sc = new Scanner(System.in);
System.out.println("输入查询的11位手机号:");
String phone = sc.nextLine();
URL url = new URL("http://apis.juhe.cn/mobile/get? phone=" + phone + "&dtype=xml&key=9f3923e8f87f1ea50ed4ec8c39cc9253");
URLConnection conn = url.openConnection(); //打开ur连接
InputStream is = conn.getInputStream(); //从url资源中获取一个输入流对象
//开始解析获取到的网络xml资源
SAXReader saxReader = new SAXReader(); //创建一个xml读取对象
Document doc = saxReader.read(is); //通过读取对象,读取xml对象,并返回文档对象
Element root = doc.getRootElement(); //获取根元素
String resultcode = root.elementText("resultcode");
if (resultcode.equals("200")) {
String reason = root.elementText("reason");
Element result = root.element("result");
String province = result.elementText("province");
String city = result.elementText("city");
String zip = result.elementText("zip");
String company = result.elementText("company");
if (city.equals(province)) {
System.out.println("手机号码的运营商:" + company + ", 归属地:" + city + ", 邮编:" + zip);
} else{
System.out.println("手机号码的运营商:" + company + ", 归属地:" + province + " " + city + ", 邮编:" + zip);
}
} else {
System.err.println("请输入正确的手机号。。。");
}
}
}
输出结果:
3. 通过XPATH解析XML
路径表达式
通过路径快速的查找一个或一组元素路径表达式:
/
: 从根节点开始查找//
: 从发起查找的节点位置 查找后代节点 ***.
: 查找当前节点 、、..
: 查找父节点@
: 选择属性. *
属性使用方式:
[@属性名='值']
[@属性名>'值']
[@属性名<'值']
[@属性名!='值']
对上面两个示例,进行XPATH优化
示例 1:
//获取输入流
FileInputStream fis = new FileInputStream("src/Demo1.xml");
//创建XML读取对象
SAXReader saxReader = new SAXReader();
//对对象进行获取读取
Document doc = saxReader.read(fis);
//通过获取到的文档对象,进行解析操作——获取xml中的根元素root
//以上部分与示例1 前半部分部分相同,
//通过XPATH解析XML,效率等同,但是代码简练
List<Node> names = doc.selectNodes("//name"); //从获取到的xml中查找所有name节点
for (int i = 0;i < element.size();i++) {
System.out.println(names.get(i).getName() + ": " + names.get(i).getText());
}
Node node1 = doc.selectSingleNode("//book[@id='1001']//name"); //根据路径表达式, 查找匹配个id属性为1001的结点的单个结点,若是查询到多个返回第一个
System.out.println("\n" + node1.getName() + ": " + node1.getText());
fis.close(); //关闭文件输入流
输出结果:
示例 2:
Scanner sc = new Scanner(System.in);
System.out.println("输入查询的11位手机号:");
String phone = sc.nextLine();
URL url = new URL("http://apis.juhe.cn/mobile/get? phone=" + phone + "&dtype=xml&key=9f3923e8f87f1ea50ed4ec8c39cc9253");
URLConnection conn = url.openConnection(); //打开ur连接
InputStream is = conn.getInputStream(); //从url资源中获取一个输入流对象
//开始解析获取到的网络xml资源
SAXReader saxReader = new SAXReader(); //创建一个xml读取对象
Document doc = saxReader.read(is); //通过读取对象,读取xml对象,并返回文档对象
//以上部分与示例2 前半部分部分相同
//通过XPATH解析XML
Node node = doc.selectSingleNode("//company");
System.out.println("手机号码的运行商:" + node.getText());
输出结果:
4. Java对象生成XML
大致步骤:
- 通过文档帮助器 (DocumentHelper) , 创建空的文档对象 Document doc = DocumentHelper.createDocument();
- 通过文档对象, 向其中添加根节点 Element root = doc.addElement(“根节点名称”);
- 通过根节点对象root , 丰富我们的子节点 Element e = root.addElement(“元素名称”);
- 创建一个文件输出流 ,用于存储XML文件 FileOutputStream fos = new FileOutputStream(“要存储的位置”);
- 将文件输出流, 转换为XML文档输出流 XMLWriter xw = new XMLWriter(fos);
- 写出文档xw.write(doc);
- 释放资源xw.close();
示例:
import org.dom4j.Document;
import org.dom4j.DocumentHelper;
import org.dom4j.Element;
import org.dom4j.io.XMLWriter;
import java.io.*;
public class Demo3 {
public static void main(String[] args) throws IOException {
//通过文档帮助器 DocumentHelper ,创建一个文档对象
Document doc = DocumentHelper.createDocument();
//给文档添加第一个节点(根节点)
Element books = doc.addElement("books");
//通过根节点,丰富子节点
for (int i = 0;i < 3 ;i++) { //循环增加三个节点
Element book = books.addElement("book"); //添加元素
Element name = books.addElement("name");
name.setText("生产者");
Element info = book.addElement("info");
info.setText("讲述了生产者的概念与特性");
book.addAttribute("id",100+i+""); //添加属性
}
//创建一个文件输出流,用于将xml文件导出
FileOutputStream fos = new FileOutputStream("src/books.xml"); //相对路径为代码本地文件src路径下
//将输出流转换为XML输出流
XMLWriter xw = new XMLWriter(fos);
//写出文档
xw.write(doc);
//释放资源
xw.close();
System.out.println("执行完毕!");
}
}
运行结果,代码执行成功,可以看到src路径下生成了一个xml文件:
打开books.xml文件查看,进行代码格式化后:
5. XStream 的使用
目的:快速的将Java中的对象, 转换为 XML字符串。
示例:
import com.thoughtworks.xstream.XStream;
public class Demo4 {
public static void main(String[] args) {
Person p = new Person();
p.setName("王二");
p.setAge(20);
//XStream的使用
//1. 创建一个XStream对象
XStream x = new XStream();
//2. 修改某个类型生成的节点 (默认为包名.类名)
x.alias("person",Person.class);
//3. 传入对象,开始生成
String xml = x.toXML(p);
System.out.println(xml);
}
//创建一个静态内部实体类Person
public static class Person{
private String name;
private int age;
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
public int getAge() {
return age;
}
public void setAge(int age) {
this.age = age;
}
}
}
运行结果:
二、JSON
JSON(JavaScript Object Notation, JS 对象简谱) 是一种轻量级的数据交换格式。它基于 ECMAScript (欧洲计算机协会制定的js规范)的一个子集,采用完全独立于编程语言的文本格式来存储和表示数据。简洁和清晰的层次结构使得 JSON 成为理想的数据交换语言。 易于人阅读和编写,同时也易于机器解析和生成,并有效地提升网络传输效率。
JSON是一种脚本语言。
与XML的比较
可读性
JSON和XML的可读性可谓不相上下,一边是简易的语法,一边是规范的标签形式,很难分出胜负。
可扩展性
XML天生有很好的扩展性,JSON当然也有,没有什么是XML可以扩展而JSON却不能扩展的。不过JSON在Javascript主场作战,可以存储Javascript复合对象,有着xml不可比拟的优势。
编码难度
XML有丰富的编码工具,比如Dom4j、Dom、SAX等,JSON也有提供的工具。无工具的情况下,相信熟练的开发人员一样能很快的写出想要的xml文档和JSON字符串,不过,xml文档要多很多结构上的字符。
解码难度
XML的解析方式有两种:
- 一是通过文档模型解析,也就是通过父标签索引出一组标记。例如:xmlData.getElementsByTagName(“tagName”),但是这样是要在预先知道文档结构的情况下使用,无法进行通用的封装。
- 另外一种方法是遍历节点(document 以及 childNodes)。这个可以通过递归来实现,不过解析出来的数据仍旧是形式各异,往往也不能满足预先的要求。
凡是这样可扩展的结构数据解析起来一定都很困难。
JSON也同样如此。如果预先知道JSON结构的情况下,使用JSON进行数据传递简直是太美妙了,可以写出很实用美观可读性强的代码。
而如果不知道JSON的结构而去解析JSON的话,那简直是噩梦。费时费力不说,代码也会变得冗余拖沓,得到的结果也不尽人意。但是这样也不影响众多前台开发人员选择JSON。因为json.js中的toJSONString()就可以看到JSON的字符串结构。当然对于不是经常使用这个字符串的人,这样做仍旧是噩梦。常用JSON的人看到这个字符串之后,就对JSON的结构很明了了,就更容易的操作JSON。
以上是在Javascript中仅对于数据传递的xml与JSON的解析。在Javascript地盘内,JSON毕竟是主场作战,其优势当然要远远优越于xml。如果JSON中存储Javascript复合对象,而且不知道其结构的话,我相信很多程序员也一样是哭着解析JSON的。
除了上述之外,JSON和XML还有另外一个很大的区别在于有效数据率。JSON作为数据包格式传输的时候具有更高的效率,这是因为JSON不像XML那样需要有严格的闭合标签,这就让有效数据量与总数据包比大大提升,从而减少同等数据流量的情况下,网络的传输压力。
1. 对象格式
一个对象, 由一个大括号表示。
括号中,描述对象的属性 。
通过键值对来描述对象的属性 (可以理解为, 大括号中, 包含的是一个个的键值对)。
格式:
加粗样式
- 键与值之间使用冒号连接, 多个键值对之间使用逗号分隔.
- 键值对的键 应使用引号引住 (通常Java解析时, 键不使用引号会报错. 而JS能正确解 析.)
- 键值对的值, 可以是JS中的任意类型的数据
数组格式:
在JSON格式中可以与对象互相嵌套
[元素1,元素2…]
示例:
{
"name":"老师", "age":18, "friends":["张三", "李四", "王二", "麻子", {"name":"语文组长", "info":"正在收语文作业" }],
"headmaster":{
"name":"定海神针", "length":"40m"
}
}
分析:整个外层的大括号表示一个对象,对象中包含name,age,friend,headmaster,而friend是属性名,属性值是一个数组:0下标是张三,1下标是李四,…,4下标是一个嵌套的对象;属性headmaster是一个嵌套的对象。
也就是说对象里面可以嵌套 对象,嵌套数组,数组里可以嵌套对象。
我们打开京东万象这个API接口平台,查找到全国天气查询。
复制下方的json,在json网站上解析查看,https://www.bejson.com/jsonviewernew/
2. Gson 与 FastJson
下载相应jar包,导入。
目的:
- 将Java中的对象 快速的转换为 JSON格式的字符串 。
- 将JSON格式的字符串, 转换为Java的对象。
谷歌的Gson
- 将对象转换为JSON字符串
转换JSON字符串的步骤:
- 引入JAR包
- 在需要转换JSON字符串的位置编写如下代码即可:
String json = new Gson().toJSON(要转换的对象);
- 将JSON字符串转换为对象
- 引入JAR包
- 在需要转换Java对象的位置, 编写如下代码:
对象 = new Gson().fromJson(JSON字符串,对象类型.class);
示例:
import com.google.gson.Gson;
import java.util.HashMap;
import java.util.List;
/**
* Gson使用
*/
public class Demo5 {
public static void main(String[] args) {
//创建Gson对象,将对象转换为Gson
Gson g = new Gson();
Book b1 = new Book("100","红富士","红富士,又大又红又甜");
String s = g.toJson(b1);
System.out.println("转换为的Gson格式:" + s);
//将Gson转换为Book对象
//有些地方需要使用'\'转义字符
Book b2 = g.fromJson("{\"id\":\"100\",\"name\":\"红富士\",\"info\":\"红富士,又大又红又甜\"}",Book.class);
System.out.println("转换为的对象格式:" + b2);
//将Gson转换为HashMap集合
HashMap data = g.fromJson("{\"id\":\"100\",\"name\":\"红富士\",\"info\":[\"农民伯伯\",\"黑土地\",\"东北的\"]}", HashMap.class);
System.out.println("该数据类型:" + data.get("info").getClass()); //会将数组部分转换为为ArrayList类型
List info = (List) data.get("info"); //使用集合接受info这个ArrayList的数据
System.out.println("种植对象:" + info.get(0));
}
}
运行结果:
FastJson
- 将对象转换为JSON字符串
- 引入JAR包
- 在需要转换Java对象的位置, 编写如下代码:
对象 = new Gson().fromJson(JSON字符串,对象类型.class);
- 将JSON字符串转换为对象
- 引入JAR包
- 在需要转换JSON字符串的位置编写如下代码即可:
String json=JSON.toJSONString(要转换的对象);
示例:
import com.alibaba.fastjson.JSON;
import java.util.HashMap;
import java.util.List;
/**
* FastJson的使用
*/
public class Demo6 {
public static void main(String[] args) {
//直接调用JSON中的toJSONString进行转换
Book b1 = new Book("1002","西游记","四个勇敢伙伴大闹西天");
String s = JSON.toJSONString(b1);
System.out.println("转换为的Gson格式:" + s);
//将JSON转换为Book对象
Book b2 = JSON.parseObject("{\"id\":\"1002\",\"info\":\"四个勇敢伙伴大闹西天\",\"name\":\"西游记\"}",Book.class);
System.out.println("转换为的对象格式:" + b2);
//将JSON转换为List<String>集合
HashMap data = JSON.parseObject("{\"id\":\"100\",\"name\":\"红富士\",\"info\":[\"农民伯伯\",\"黑土地\",\"东北的\"]}", HashMap.class);
System.out.println("该数据类型:" + data.get("info").getClass()); //会将数组部分转换为为ArrayList类型
List info = (List) data.get("info"); //使用集合接受info这个ArrayList的数据
System.out.println("种植对象:" + info.get(0));
}
}
运行结果: