Java之 XML与JSON(公众平台接口数据格式)

  • 1. XML
  • 2. XML语法
  • 2.1XML文档声明
  • 2.2 标记(元素/标签/节点)
  • 2.3 一个XML文档中,必须有且且仅允许有一个根标记
  • 2.4 标记可以嵌套,但是不允许交叉
  • 2.5 标记的层级称呼(子标记,父标记,兄弟标记,后代标记,祖先标记)
  • 2.6 标记名称
  • 2.7 标记除了开始和结束,还有属性
  • 2.8 注释
  • 2.9 语法进阶CDATA
  • 3. XML解析(外部库DOM4J)
  • 3.1 DOM4J解析XML
  • 3.2 文档对象Document
  • 3.3 元素对象Element
  • 4. XPATH解析
  • 5. XML生成
  • 6. Java对象转换XML(外部库XStream)
  • 7. 解析XML的四种方式
  • 7.1 SAX解析
  • 7.2 DOM解析
  • 7.3 JDOM解析
  • 7.4 DOM4J解析
  • 8. JSON
  • 9. GSON解析JSON(外部库gson)
  • 9.1 将对象转换为JSON字符串
  • 9.2 将JSON字符串转换为对象
  • 10. FastJson解析JSON(外部库fastjson)
  • 10.1 将对象转换为JSON字符串
  • 10.2 将JSON字符串转换为对象


1. XML

概念: 可扩展标记语言(即可自定义标签名称)(eXtensible Markup Language)。用于不同语言之间的数据交流。

特性:

  1. xml具有平台无关性,是一门独立的标记语言。
  2. xml具有自我描述性

XML应用领域:

  1. 网络数据传输(使用JSON更好)
  2. 数据存储(一般不使用)
  3. 配置文件(主要应用领域)

XML文件:

  • .XML文件是保存XML数据的一种方式
  • XML数据也可以以其他的方式存在(如在内存中构建XML数据)。
  • 不要将XML语言狭隘的理解成XML文件

2. XML语法

2.1XML文档声明

<?xml version=”1.0” encoding=”UTF-8”?>

2.2 标记(元素/标签/节点)

XML文档是由一个个的标记组成。
语法:

  • 开始标记(开放标记):<标记名称>
  • 结束标记(闭合标记):</标记名称>

标记名称: 自定义名称,必须遵循以下命名规则:
1、 名称可以含字母、数字以及其他的字符
2、 名称不能以数字或者标点符号开始
3、 名称不能以字符 “xml”(或者 XML、Xml)开始
4、 名称不能包含空格,不能包含冒号(:)
5、 名称区分大小写

标记内容: 开始标记与结束标记之间,是标记的内容。
例如:我们通过标记,描述一个人名:李伟杰

2.3 一个XML文档中,必须有且且仅允许有一个根标记

正例:

<names>
	<name>张三</name>
	<name>李四</name>
</names>

反例:

<name>李四</name>
<name>麻子</name>``

2.4 标记可以嵌套,但是不允许交叉

正例:

<person>
	<name>李四</name>
	<age>18 </age>
</person>

反例:

<person>
	<name>李四<age></name>
	18</age>
</person>

2.5 标记的层级称呼(子标记,父标记,兄弟标记,后代标记,祖先标记)

例如:

<persons>
	<person>
		<name>李四</name>
		<length>180cm</length>
	</person>
	<person>
		<name>李四</name>
		<length>200cm</length>
	</person>
</persons>

1、 name是person的子标记,也是person的后代标记
2、 name是persons的后代标记。
3、 name是length的兄弟标记。
4、 person是name的父标记。
5、 persons是name的祖先标记。

2.6 标记名称

允许重复

2.7 标记除了开始和结束,还有属性

标记中的属性,在标记开始时描述,由属性名和属性值组成。
格式:

  • 在开始标记中,描述属性。
  • 可以包含0-n个属性,每一个属性是一个键值对!
  • 属性名不允许重复,键与值之间使用等号连接,多个属性之间使用空格分割。
  • 属性值必须被引号引住。

案例:

<persons>
	<person id=”1001” groupid=”1”>
		<name>李四</name>
		<length>180cm</length>
	</person>
	<person id=”1002” groupid=”1”>
		<name>李四</name>
		<length>200cm</length>
	</person>
</persons>

2.8 注释

注释不能写在文档的文档声明前。注释不能嵌套注释。

格式:

  • 注释开始:<!--
  • 注释结束:-->

案例:
描述一组图书books,至少包含3本书。图书book包含:图书名称name,图书简介info,以及属性id。

<?xml version=”1.0” encoding=”UTF-8”?>
<books>
	… …
</books>

2.9 语法进阶CDATA

概念: CDATA是不会被XML解析器解析的文本数据. 像"<“和”&“字符在XML元素中都是非法的。”<“会产生错误,因为解析器会把该字符解释为新元素的开始。”&“会产生错误,因为解析器会把该字符解释为字符实体的开始。某些文本,比如JavaScript代码,包含大量”<“或”&"字符。为了避免错误,可以将脚本代码定义为CDATA。CDATA部分中的所有内容都会被解析器忽略。CDATA部分由“<![CDATA[”开始,由“]]>”结束。
格式: <![CDATA[...]]>

3. XML解析(外部库DOM4J)

3.1 DOM4J解析XML

步骤:

  1. 引入jar文件dom4j.jar
  2. 创建一个指向XML文件的输入流
FileInputStream fis = new FileInputStream("xml文件的地址");
  1. 创建一个XML读取工具对象
SAXReader sr = new SAXReader();
  1. 使用读取工具对象,读取XML文档的输入流,并得到文档对象
Document doc = sr.read(fis);
  1. 通过文档对象, 获取XML文档中的根元素对象
Element root = doc.getRootElement();

3.2 文档对象Document

概念: 指的是加载到内存的 整个XML文档。
常用方法:

  • 通过文档对象,获取XML文档中的根元素对象
Element root = doc.getRootElement();
  • 添加根节点
Element root = doc.addElement("根节点名称");

3.3 元素对象Element

概念: 指的是XML文档中的单个节点。
常用方法:

变量和类型

方法

描述

String

getName()

获取节点名称

String

getText()

获取节点内容

String

setText()

设置节点内容

Element

element(String 子节点名称)

根据子节点的名称,获取匹配名称的第一个子节点对象。

List

elements()

获取所有的子节点对象

String

attributeValue(String 属性名称)

获取节点的属性值

String

elementText(String 子节点名称)

获取子节点的内容

Element

addElement(String 子节点名称)

添加子节点

void

addAttribute(String 属性名,String 属性值)

添加属性

eg:

/**
 * DOM4J解析本地XML文件案例
 */
public static void main(String[] args) throws IOException, DocumentException {
    //1.    创建指向XML文件的输入流
    FileInputStream fis = new FileInputStream("book.xml");
    //2.    创建一个XML读取工具对象
    SAXReader sr = new SAXReader();
    //3.    读取XML文档的输入流对象
    Document doc = sr.read(fis);
    //4.    获取XML文档根元素对象
    Element root = doc.getRootElement();
    //5.    开始解析文档
    System.out.println(root.getName());
    List<Element> es = root.elements();
    for (int i = 0; i < es.size(); i++) {
        Element book = es.get(i);
        System.out.println(book.attributeValue("id"));
        System.out.println(book.elementText("name"));
        System.out.println(book.elementText("info"));
        System.out.println("-----------------------------");
    }
    fis.close();
}
/**
 * DOM4J解析网络XML文件案例
 */
public static void main(String[] args) throws IOException, DocumentException {
    String phone = "18516955565";
    //1.    获取XML输入流
    URL url = new URL("http://apis.juhe.cn/mobile/get?phone="+phone+"&dtype=xml&key=9f3923e8f87f1ea50ed4ec8c39cc9253");
    URLConnection conn = url.openConnection();
    InputStream is = conn.getInputStream();
    //2.    创建XML读取对象
    SAXReader sr = new SAXReader();
    //3.    读取XML数据,返回文档对象
    Document doc = sr.read(is);
    //4.    获取根节点
    Element root = doc.getRootElement();
    //5.    解析内容
    String code = root.elementText("resultcode");
    if ("200".equals(code)){
        Element result = root.element("result");
        String province = result.elementText("province");
        String city = result.elementText("city");
        if (province.equals(city)){
            System.out.println("号码归属地为:"+city);
        }else {
            System.out.println("号码归属地为:"+province+" "+city);
        }
    }else {
        System.out.println("请输入正确的手机号码!");
    }
}

4. XPATH解析

路径表达式: 通过路径快速的查找一个或一组元素。
路径表达式格式

  1. /:从根节点开始查找
  2. //:从发起查找的节点位置 查找后代节点 ***
  3. .:查找当前节点
  4. ..:查找父节点
  5. @:选择属性. *
    属性使用方式:
  • [@属性名='值']
  • [@属性名>'值']
  • [@属性名<'值']
  • [@属性名!='值']

使用步骤:
通过Node类的两个方法,来完成查找:(Node是Document与Element的父接口)
方法1:根据路径表达式查找匹配的单个节点

Element e = doc.selectSingleNode("路径表达式");

方法2:根据路径表达式查找匹配的所有节点

List<Element> es = doc.selectNodes("路径表达式");

eg:

/**
 * XPATH解析本地XML文件案例
 */
public static void main(String[] args) throws IOException, DocumentException {
    //1.    创建指向XML文件的输入流
    FileInputStream fis = new FileInputStream("book.xml");
    //2.    创建一个XML读取工具对象
    SAXReader sr = new SAXReader();
    //3.    读取XML文档的输入流对象
    Document doc = sr.read(fis);
    //4.    开始解析文档
   /* List<Element> names = doc.selectNodes("//book[@id=1001]//name");
    for (int i = 0; i < names.size(); i++) {
        System.out.println(names.get(i).getName()+":"+names.get(i).getText());
    }*/
    Node n = doc.selectSingleNode("//book[@id=1002]//name");
    System.out.println(n.getName()+":"+n.getText());
    fis.close();
}
/**
 * Java解析网络XML文件案例
 */
public static void main(String[] args) throws IOException, DocumentException {
    String phone = "18516955565";
    //1.    获取XML输入流
    URL url = new URL("http://apis.juhe.cn/mobile/get?phone="+phone+"&dtype=xml&key=9f3923e8f87f1ea50ed4ec8c39cc9253");
    URLConnection conn = url.openConnection();
    InputStream is = conn.getInputStream();
    //2.    创建XML读取对象
    SAXReader sr = new SAXReader();
    //3.    读取XML数据,返回文档对象
    Document doc = sr.read(is);
    //4.    解析内容
    Node node = doc.selectSingleNode("//company");
    System.out.println("运营商:"+node.getText());
}

5. XML生成

生成步骤:

  1. 通过文档帮助器 (DocumentHelper),创建空的文档对象
Document doc = DocumentHelper.createDocument();
  1. 通过文档对象,向其中添加根节点
Element root = doc.addElement("根节点名称");
  1. 通过根节点对象root,丰富我们的子节点
Element e = root.addElement("元素名称");
  1. 创建一个文件输出流,用于存储XML文件
FileOutputStream fos = new FileOutputStream("要存储的位置");
  1. 将文件输出流,转换为XML文档输出流
XMLWriter xw = new XMLWriter(fos);
  1. 写出文档
xw.write(doc);
  1. 释放资源
xw.close();

eg:

/**
 *生成XML
 */
public static void main(String[] args) throws IOException {
    //1.    同过文档帮助器生成空文档对象
    Document doc = DocumentHelper.createDocument();
    //2.    向文档对象中加入根节点对象
    Element books = doc.addElement("books");
    //3.    向根节点中丰富子节点
    for (int i = 0; i < 10; i++) {
        Element book = books.addElement("book");
        book.addAttribute("id",1+i+"");
        Element name = book.addElement("name");
        Element info = book.addElement("info");
        name.setText("Java学员");
        info.setText("天天学习");
    }
    //4.    创建文件的输出流
    FileOutputStream fos = new FileOutputStream("books.xml");
    //5.    将文件输出流转换为xml输出流
    XMLWriter xw = new XMLWriter(fos);
    //6.    写出xml文档
    xw.write(doc);
    //7.    释放资源
    xw.close();
    System.out.println("程序执行完毕!");
}

6. Java对象转换XML(外部库XStream)

概念: 快速的将Java中的对象,转换为XML字符串。
使用步骤:

  1. 创建XStream对象
XStream x = new XStream();
  1. 修改类生成的节点名称(默认节点名称为包名.类名)
x.alias("节点名称",类名.class);
  1. 传入对象,生成XML字符串
String xml字符串 = x.toXML(对象);

eg:

/**
 * XStream的使用
 */
public static void main(String[] args) {
    Person p = new Person("张三",18);
    //1.    创建XStream对象
    XStream x = new XStream();
    //2.    修改类生成的节点名称(默认为包名.类名)
    x.alias("person",Person.class);
    //3.    传入对象,生成XML字符串
    String xml = x.toXML(p);
    System.out.println(xml);
}
static class Person{
    public Person(String name, int age) {
        this.name = name;
        this.age = age;
    }
    private String name;
    private int age;
}

7. 解析XML的四种方式

7.1 SAX解析

概念: 解析方式是事件驱动机制! SAX解析器,逐行读取XML文件解析,每当解析到一个标签的开始/结束/内容/属性时,会触发事件。我们可以编写程序在这些事件发生时,进行相应的处理。
优点:

  1. 分析能够立即开始,而不是等待所有的数据被处理
  2. 逐行加载,节省内存。有助于解析大于系统内存的文档
  3. 有时不必解析整个文档,它可以在某个条件得到满足时停止解析。
    缺点:
  4. 单向解析,无法定位文档层次,无法同时访问同一文档的不同部分数据(因为逐行解析,当解析第n行时,第n-1行已经被释放了,无法在进行操作了)。
  5. 无法得知事件发生时元素的层次,只能自己维护节点的父/子关系。
  6. 只读解析方式,无法修改XML文档的内容。

7.2 DOM解析

概念: 是用与平台和语言无关的方式表示XML文档的官方W3C标准,分析该结构通常需要加载整个文档和在内存中建立文档树模型。程序员可以通过操作文档树,来完成数据的获取、修改、删除等。
优点:
文档在内存中加载,允许对数据和结构做出更改。
访问是双向的,可以在任何时候在树中双向解析数据。
缺点: 文档全部加载在内存中,消耗资源大。(一般非常小,忽略不计)

7.3 JDOM解析

概念: 目的是成为Java特定文档模型,它简化与XML的交互并且比使用DOM实现更快。由于是第一个Java特定模型,JDOM一直得到大力推广和促进。JDOM文档声明其目的是“使用20%(或更少)的精力解决80%(或更多)Java/XML问题”(根据学习曲线假定为20%)
优点:
使用具体类而不是接口,简化了DOM的API。
大量使用了Java集合类,方便了Java开发人员。
缺点: 没有较好的灵活性。性能不是那么优异。

7.4 DOM4J解析

概念:

  • 它是JDOM的一种智能分支。它合并了许多超出基本XML文档表示的功能,包括集成的XPath支持、XML Schema支持以及用于大文档或流化文档的基于事件的处理。它还提供了构建文档表示的选项, DOM4J是一个非常优秀的Java XML API,具有性能优异、功能强大和极端易用使用的特点,同时它也是一个开放源代码的软件。如今你可以看到越来越多的Java软件都在使用DOM4J来读写XML。
  • 目前许多开源项目中大量采用DOM4J , 例如:Hibernate

8. JSON

概念: JSON(JavaScript Object Notation)JS对象简谱,是一种轻量级的数据交换格式。传输速度比XML快可以将Java中的对象快速的转换为JSON格式的字符串。将JSON格式的字符串,转换为Java的对象。
表示对象的格式:
一个对象由一个大括号表示。括号中描述对象的属性。通过键值对来描述对象的属性。(可以理解为,大括号中,包含的是一个个的键值对。)

  1. 键与值之间使用冒号连接,多个键值对之间使用逗号分隔。
  2. 键值对的键应使用引号引住(通常Java解析时,键不使用引号会报错。而JS能正确解析。)
  3. 键值对的值,可以是JS中的任意类型的数据。

eg:

java:
class Book{
	private String name;
	private String info;
	get/set... 
}
Book b = new Book();
b.setName(“金苹果”);
b.setInfo(“种苹果”);
...
js:
var b = new Object();
b.name = "金苹果";
b.info = "种苹果";
XML:
<book>
	<name>金苹果</name>
	<info>种苹果</info>
</book>
JSON:
{
	"name":"金苹果",
	"info":"种苹果"
}

数组格式:
在JSON格式中可以与对象互相嵌套

[元素1,元素2...]

eg:

{
	"name":"伟杰老师",
	"age":18,
	"pengyou":["张三","李四","王二","麻子",{
			"name":"野马老师",
			"info":"像匹野马一样狂奔在技术钻研的道路上"
		}],
	"heihei":{
		"name":"大长刀",
		"length":"40m"
	}
}

9. GSON解析JSON(外部库gson)

9.1 将对象转换为JSON字符串

转换为JSON字符串的步骤:

  1. 引入JAR包
  2. 在需要转换JSON字符串的位置,编写如下代码:
String json = new Gson().toJSON(要转换的对象);

eg:

Book b = BookDao.find();
String json = new Gson().toJson(b);
System.out.println(json);

9.2 将JSON字符串转换为对象

转换为对象的步骤:

  1. 引入JAR包
  2. 在需要转换Java对象的位置,编写如下代码:
对象 = new Gson().fromJson(JSON字符串,对象类型.class);
  1. 也可以转换为集合类型:
HashMap map = new Gson().fromJson(JSON字符串, HashMap.class);

注意: 如果JSON字符串的值中包含数组,则该值(数组)会转换为ArrayList类型!

eg:

String json = "{\"id\":1,\"name\":\"金苹果\",\"author\":\"李伟杰
\",\"info\":\"嘿嘿嘿嘿嘿嘿\",\"price\":198.0}";
    Book book = new Gson().fromJson(json, Book.class);
    System.out.println(book);

10. FastJson解析JSON(外部库fastjson)

10.1 将对象转换为JSON字符串

转换为JSON字符串的步骤:
1、 引入JAR包
2、 在需要转换Java对象的位置,编写如下代码:

String json=JSON.toJSONString(要转换的对象);

eg:

Book b = BookDao.find();
String json=JSON.toJSONString(b);
System.out.println(json);

10.2 将JSON字符串转换为对象

转换为对象的步骤:
1、 引入JAR包
2、 在需要转换Java对象的位置,编写如下其一的代码:

1.	类型 对象名=JSON.parseObject(JSON字符串, 类型.class);
2.	List<类型> list=JSON.parseArray(JSON字符串,类型.class);

eg:

String json = "{\"id\":1,\"name\":\"金苹果\",\"author\":\"李伟杰
\",\"info\":\"嘿嘿嘿嘿嘿嘿\",\"price\":198.0}";
    Book book = JSON.parseObject(json, Book.class);
    System.out.println(book);