前言
今日学习内容:XML和JSON
一、XML
1、简介
XML 可扩展标记语言(extensible Markup Language)
可扩展 -- > 标记可扩展
特性:
1. xml具有平台无关性(无论哪种语言解析、无论哪类系统加载)
2. xml具有自我描述性 (通俗易懂,类自我介绍)
3. xml是一种标记语言,很类似 html(标记是一种特殊的语法)
4. xml的设计宗旨是**传输数据**,而非显示数据
5. xml**标签没有被预定义**,而html都是预定义标签
6. xml是 W3C 的推荐标准
2、为什么学习xml
1. 网络数据传输(更多用JSON)
*问题:一个登录请求 需要传送账号、密码 一串字符串
如何进行拆解??? 不一样的分割符号 不一样的分割标准 -->统一格式*
2. 数据存储(使用较少)
3. 配置文件(学习重点,学会编写)
3、扫盲
-.XML文件是保存XML数据的一种方式
- xml json 本质上都是字符串
- XML数据也可以以其他的方式存在(如在内存中构建XML数据)
- 不要将XML语言狭隘的理解成XML文件
4、xml语法格式
<?xml version="1.0" encoding="UTF-8"?>
- 标记 ( 元素 / 标签 / 节点):XML文档由一个个的标记组成
- 语法
开始标记(开放标记): <标记名称>
结束标记(闭合标记): </标记名称>
1.名称可以含字母、数字以及其他的字符
2.名称不能以数字或者标点符号开始
3.名称不能以字符 “xml”(或者 XML、Xml)开始
4.名称不能包含空格,不能包含冒号(:)
5.名称区分大小写
- 标记内容: 开始标记与结束标记之间 ,是标记的内容.
5、语法重点
一个XML文档中, 必须有且且仅允许有一个根标记
正例:
<names>
<name>张三</name>
<name>李四</name>
</names>
反例:
<name>李四</name>
<name>麻子</name>
标记可以嵌套, 但是不允许交叉
正例:
<person>
<name>李四</name>
<age>18</age>
</person>
反例:
<person>
<name>李四<age></name>
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>
注释
注释不能写在文档文档声明前
注释不能嵌套注释
·格式:
注释开始:
可以用记事本的格式创建文档进行编写练习
案例:
<?xml version = "1.0" encoding = "UTF-8"?>
<books>
<book id = "1001">
<id>1001</id>
<name>金苹果</name>
<info>描述了金苹果的种植过程</info>
</book>
<book id = "1002">
<name>银苹果</name>
<info>描述了银苹果的种植过程</info>
</book>
</books>
二、xml解析
1、SAX解析
优点:
1. 分析能够立即开始,而不是等待所有的数据被处理
2. 逐行加载,节省内存 有助于解析大于系统内存的文档
3. 有时不必解析整个文档,它可以在某个条件的到满足时停止解析
缺点:
1. 单向解析,无法定位文档层次,无法同时访问同一文档的不同部分数据(因为逐行解析,当解析第N行时,第N-1行已经被释放了,无法再进行操作)
2. 无法得知事件发生时元素的层次,只能自己维护节点的父/子关系
3. 只读解析方式,无法修改xml文档的内容
2、DOM解析
是用与平台和语言无关的方式表示xml文档的官方w3c标准,分析该结构通常需要加载整个文档和内存中建立文档树模型。程序员可以通过操作文档树,来完成数据的获取、修改、删除等
优点:
1. 文档在内存中加载,允许对数据和结构做出更改
2. 访问是双向的,可以在任何时候在树中双向解析数据
缺点:
文档全部加载在内存中,消耗资源大
3、JDOM解析
目的是成为Java特定文档模型,它简化与XML的交互并且比使用DOM实现更快。由于是第一 个Java特定模型,JDOM一直得到大力推广和促进。
JDOM文档声明其目的是“使用20%(或更少)的精力解决80%(或更多)Java/XML问题” (根据学习曲线假定为20%)
优点:
1. 使用具体类而不是接口,简化了DOM的API
2. 大量使用了Java集合类,方便了Java开发人员
缺点:
1. 没有较好的灵活性
2. 性能不是那么优异
4、DOM4J解析
它是JDOM的一种智能分支。合并了许多超出基本XML文档表示的功能,
包括集成的XPath 支持、XML Schema支持以及用于大文档或流化文档的基于事件的处理。
它还提供了构建文档表示的选项, DOM4J是一个非常优秀的Java XML API,
具有性能优异、功能强大和极端易用使用的特点;
同时它也是一 个开放源代码的软件。如今你可以看到越来越多的Java软件都在使用DOM4J来读写XML。
目前许多开源项目中大量采用DOM4J , 例如:Hibernate
三、SAX解析实例
1、解析本地文件
Demo1.xml
<?xml version="1.0" encoding="UTF-8"?>
<books>
<book id = "1001">
<name>金苹果</name>
<info>锄禾日当午</info>
</book>
<book id = "1002">
<name>银苹果</name>
<info>汗滴禾下土</info>
</book>
<book id = "1003">
<name>红苹果</name>
<info>谁知盘中餐</info>
</book>
<book id = "1004">
<name>青苹果</name>
<info>粒粒皆辛苦</info>
</book>
</books>
Demo1.java
package demoXML;
import org.dom4j.Document;
import org.dom4j.DocumentException;
import org.dom4j.Element;
import org.dom4j.io.SAXReader;
import java.io.FileInputStream;
import java.io.IOException;
import java.util.List;
public class Demo1 {
/*
* 解析本地文件
* */
public static void main(String[] args) throws IOException, DocumentException {
//1. 获取指向xml文件的输入流(注意文件一定要是xml结尾的)
FileInputStream fis = new FileInputStream("B://Demo1.xml");
//2.创建XML读取对象(用SAX读取)
SAXReader sr = new SAXReader();
//3.读取并得到文档对象
Document doc = sr.read(fis);
//4.通过文档获取根元素
Element root = doc.getRootElement();
//5.开始解析元素
System.out.println(root.getName());
//6.从根节点root开始层层搜索
Element book = root.element("book");
Element name = book.element("name");
Element info = book.element("info");
System.out.println(name.getText());
System.out.println(info.getText());
//7.遍历子节点内容
List<Element> es = root.elements();
for (int i = 0; i < es.size(); i++) {
Element book_i = es.get(i);
//1.获取booK 中的id属性值
System.out.println(book_i.attributeValue("id"));
//2.获取book 中子节点name的文本值
System.out.println(book_i.elementText("name"));
//3.获取book 中子节点info的文本值
System.out.println(book_i.elementText("info"));
System.out.println("--------------");
}
//8.关闭资源
fis.close();
}
}
Element类提供的方法
Method | Comment |
---|
getQName() | 元素的QName对象 | getNamespace() | 元素所属的Namespace对象 | getNamespacePrefix() | 元素所属的Namespace对象的prefix | getNamespaceURI() | 元素所属的Namespace对象的URL | getName() | 元素的Local name | getQualifiedName() | 元素的qualified name | getText() | 元素所含有的text内容,如果内容为空则返回一个空字符串而不是Null | getTextTrim() | 元素所含有的text内容,其中连续的空格被转化为单个空格,该方法不会返回null | attributeIterator() | 元素属性的iterator,其中每个元素都是Attribute对象 | attributeValue() | 元素的某个指定属性所含的值 | elementIterator() | 元素的子元素的iterator,其中每个元素都是Element对象 | element() | 元素的某个指定(qualified name或者local name)的子元素 | elementText() | 元素的某个指定(qualified name或者local name)的子元素中的text信息 | getParent | 元素的父元素 | getPath() | 元素的XPath表达式,其中父元素的qualified name和子元素的qualified name之间使用"/"分隔 | isTextOnly() | 是否该元素只含有text或是空元素 | isRootElement() | 是否该元素是XML树的根节点 |
2、解析网络文件
地址:[https://apis.juhe.cn/mobile/get?%20phone=15363397414&dtype=xml&key=9f3923e8f87f1ea50ed4ec8c39cc9253]
Demo2.java
package demoXML;
import org.dom4j.Document;
import org.dom4j.DocumentException;
import org.dom4j.Element;
import org.dom4j.io.SAXReader;
import java.io.IOException;
import java.io.InputStream;
import java.net.URL;
import java.net.URLConnection;
public class Demo2 {
public static void main(String[] args) throws IOException, DocumentException {
String phone = "18826584526";
//1.获取到XML资源的输入流
//(1) 新建一个地址对象
URL url = new URL("http://apis.juhe.cn/mobile/get? phone="+ phone +"&dtype=xml&key=9f3923e8f87f1ea50ed4ec8c39cc9253");
//(2) 打开与地址的连接
URLConnection conn = url.openConnection();
//(3) 通过连接conn获取输入流
InputStream is = conn.getInputStream();
//2.创建一个xml读取对象
SAXReader sr = new SAXReader();
//3.通过读取对象 读取xml数据 并返回文档对象
Document doc = sr.read(is);
//4.获取根节点
Element root = doc.getRootElement();
//5.解析内容
//获取根节点root下的子节点resultcode的值
String code = root.elementText("resultcode");
if(code.equals("200")){
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("手机号" + phone + "的归属地为:" + province + "省" + city + "市");
}
}else {
System.out.println("请输入正确的手机号码/网址");
}
//6.关闭资源
is.close();
}
}
四、XPATH解析
1、通过路径快速查找一个或一组元素
2、路径表达式
1. / : 从根节点开始查找
2. // : 从发起查找的节点位置 查找后代节点 ***
3. . : 查找当前节点
4. .. : 查找父节点
5. @ : 选择属性.
属性使用方式:
[@属性名='值'] [@属性名>'值'] [@属性名<'值'] [@属性名!='值']
books: 路径: //book[@id='1']//name
books
book id=1
name
info
book id=2
name
info
3、使用步骤
通过Node类的两个方法, 来完成查找:
(Node是 Document 与 Element 的父接口)
方法1.
//根据路径表达式, 查找匹配的单个节点
Element e = selectSingleNode("路径表达式");
方法2.
List<Element> es = selectNodes("路径表达式");
4、案例
Demo3.java – 解析本地文件(Demo1.xml)
package demoXML;
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;
public class Demo3 {
/*
* Xpath解析Demo1.xml
* */
public static void main(String[] args) throws IOException, DocumentException {
//1. 获取指向xml文件的输入流
FileInputStream fis = new FileInputStream("B://Demo1.xml");
//2.创建XML读取对象
SAXReader sr = new SAXReader();
//3.读取并得到文档对象
Document doc = sr.read(fis);
//4.通过文档对象+xpath 查找所有的name节点
List<Node> names = doc.selectNodes("//name");
for (int i = 0; i < names.size(); i++) {
//获取子节点的标记名
System.out.println(names.get(i).getName());
//获取该子节点下的值
System.out.println(names.get(i).getText());
}
//5.精准路径 -- > 只查询id为1001的name
List<Node> name_1 = doc.selectNodes("//book[@id = '1001']//name");
System.out.println(name_1.get(0).getText());
//6.当只有一条记录,可以采用下面这种方法
Node node = doc.selectSingleNode("//book[@id = '1001']//name");
System.out.println(node.getName() + ":" + node.getText());
//7.关闭资源
fis.close();
}
}
Demo4.java – 解析网络文件
package demoXML;
import org.dom4j.Document;
import org.dom4j.DocumentException;
import org.dom4j.Node;
import org.dom4j.io.SAXReader;
import java.io.FileInputStream;
import java.io.IOException;
import java.util.List;
public class Demo3 {
/*
* Xpath解析Demo1.xml
* */
public static void main(String[] args) throws IOException, DocumentException {
//1. 获取指向xml文件的输入流
FileInputStream fis = new FileInputStream("B://Demo1.xml");
//2.创建XML读取对象
SAXReader sr = new SAXReader();
//3.读取并得到文档对象
Document doc = sr.read(fis);
//4.通过文档对象+xpath 查找所有的name节点
List<Node> names = doc.selectNodes("//name");
for (int i = 0; i < names.size(); i++) {
//获取子节点的标记名
System.out.println(names.get(i).getName());
//获取该子节点下的值
System.out.println(names.get(i).getText());
}
//5.精准路径 -- > 只查询id为1001的name节点
List<Node> name_1 = doc.selectNodes("//book[@id = '1001']//name");
System.out.println(name_1.get(0).getText());
//6.当只有一条记录,可以采用下面这种方法
Node node = doc.selectSingleNode("//book[@id = '1001']//name");
System.out.println(node.getName() + ":" + node.getText());
//7.关闭资源
fis.close();
}
}
五、生成XML
1、Java生成xml文件
(1)步骤
1. 通过文档帮助器 (DocumentHelper) , 创建空的文档对象
Document doc = DocumentHelper.createDocument();
2. 通过文档对象, 向其中添加根节点
Element root = doc.addElement("根节点名称");
3. 通过根节点对象root , 丰富我们的子节点
Element e = root.addElement("元素名称");
4. 创建一个文件输出流 ,用于存储XML文件
FileOutputStream fos = new FileOutputStream("要存储的位置");
5. 将文件输出流, 转换为XML文档输出流
XMLWriter xw = new XMLWriter(fos);
6. 写出文档
xw.write(doc);
7. 释放资源
xw.close();
(2)实例
package demoXML;
import jdk.internal.util.xml.XMLStreamException;
import org.dom4j.Document;
import org.dom4j.DocumentHelper;
import org.dom4j.Element;
import org.dom4j.io.XMLWriter;
import java.io.FileOutputStream;
import java.io.IOException;
public class Demo5 {
public static void main(String[] args) throws XMLStreamException, IOException {
//1. 通过文档帮助器 (DocumentHelper) , 创建一个空的文档对象
Document doc = DocumentHelper.createDocument();
//2. 通过文档对象, 向其中添加根节点(第一个节点)
Element root = doc.addElement("students");
//3. 通过根节点对象root , 丰富子节点
for (int i = 0; i < 5; i++) {
Element student = root.addElement("student");
Element name = student.addElement("name");
name.setText("李" + i);
Element age = student.addElement("age");
age.setText(" " + (i + 1)*2);
student.addAttribute("id",1000 + i + "");
}
//4. 创建一个文件输出流 ,用于存储XML文件
FileOutputStream fos = new FileOutputStream("B://students.xml");
//5. 将文件输出流, 转换为XML文档输出流
XMLWriter xw = new XMLWriter(fos);
//6. 写出文档
xw.write(doc);
//7. 释放资源
xw.close();
System.out.println("执行完毕!");
}
}
生成结果 students.xml
<?xml version="1.0" encoding="UTF-8"?>
<students>
<student id="1000">
<name>李0</name>
<age>2</age>
</student>
<student id="1001">
<name>李1</name>
<age>4</age>
</student>
<student id="1002">
<name>李2</name>
<age>6</age>
</student>
<student id="1003">
<name>李3</name>
<age>8</age>
</student>
<student id="1004">
<name>李4</name>
<age>10</age>
</student>
</students>
2、XStream生成xml文件
package demoXML;
import com.thoughtworks.xstream.XStream;
/*
* 使用XStream生成Xml文件
* */
public class Demo6 {
public static void main(String[] args) {
Person p = new Person();
p.setName( "易拉罐" );
p.setAge( 22 );
//XStream的使用 -- > 生成XML文件
//1.创建XStream对象
XStream x = new XStream();
//2.修改生成的根节点(可选,默认为“包名.类名”
x.alias( "person",Person.class);
//3.传入对象p 开始生成xml
String xml = x.toXML(p);
//4.输出xml文件格式的p对象
System.out.println(xml);
}
static class Person{
private String name;
private int age;
public Person() {
}
@Override
public String toString() {
return "Person{" +
"name='" + name + '\'' +
", age=" + 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
1、简介
JavaScript Object Notation JS对象简谱 , 是一种轻量级的数据交换格式
2、对象格式
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" : ""
}
3、数组格式
在JSON格式中可以与对象互相嵌套
[元素1,元素2...]
数组钟可以包含多种数据类型
4、案例
一个对象, 由一个大括号表示.
括号中 描述对象的属性 . 通过键值对来描述对象的属性
(可以理解为, 大括号中, 包含的是一个个的键值对.)
格式:
1.键与值之间使用冒号连接, 多个键值对之间使用逗号分隔.
2.键值对的键 应使用引号引住 (通常Java解析时, 键不使用引号会报错. 而JS能正确解 析.)
3.键值对的值, 可以是JS中的任意类型的数据
{
"name":"伟杰老师",
"age":18,
"pengyou":["张三", "李四", "王二", "麻子", {
"name":"野马老师",
"info":"像匹野马一样狂奔在技术钻研的道路上"
}],
"heihei":{ "name":"大长刀",
"length":"40m"
}
}
5、缺点
无限嵌套 难以理解
6、解析JSON文件
Book.class
package demoJSON;
public class Book {
private String id;
private String name;
private String info;
public Book() {
}
public Book(String id, String name, String info) {
this.id = id;
this.name = name;
this.info = info;
}
@Override
public String toString() {
return "Book{" +
"id='" + id + '\'' +
", name='" + name + '\'' +
", info='" + info + '\'' +
'}';
}
public String getId() {
return id;
}
public void setId(String id) {
this.id = id;
}
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
public String getInfo() {
return info;
}
public void setInfo(String info) {
this.info = info;
}
}
1、谷歌 Gson
/*
* 使用谷歌Gson 对象 --> JSON格式的对象
* */
public static void main(String[] args) {
//1. 创建Gson对象
Gson gson = new Gson();
//2. 转换
Book book = new Book("100", "金苹果", "种植苹果真幸苦!");
String s = gson.toJson( book );
System.out.println(s);
//使用匿名对象
Book book1 = new Book("100", "金苹果", "种植苹果真幸苦!");
String s1 = new Gson().toJson( book );
System.out.println(s1);
}
/*
* 使用谷歌Gson JSON格式的对象 --> Book.class类型对象
* */
public static void main(String[] args) {
//1.创建Gson对象
Gson gson = new Gson();
//2.转换 {"id":"100","name":"金苹果","info":"种植苹果真幸苦!"}
Book book = gson.fromJson( "{\"id\":\"100\",\"name\":\"金苹果\",\"info\":\"种植苹果真幸苦!\"}",Book.class);
System.out.println(book.getId());
}
/*
* 使用谷歌Gson JSON格式的对象(嵌套数组) --> HashMap.class类型对象
* */
public static void main(String[] args) {
//1.创建Gson对象
Gson gson = new Gson();
//2.转换 {"id":"100","name":"金苹果","info":"种植苹果真幸苦!","page":["嘻嘻","哈哈","嘿嘿"]}
HashMap data = gson.fromJson( "{\"id\":\"100\",\"name\":\"金苹果\",\"info\":\"种植苹果真幸苦!\",\"page\":[\"嘻嘻\",\"哈哈\",\"嘿嘿\"]}", HashMap.class );
//3.当解析的内容包含数组(page)时,解析后会生成list对象的数据
List page = (List) data.get("page");
System.out.println(page.get(2));
}
2、阿里云 FastJson
/*
* 使用阿里云FastJson 对象 --> JSON格式的对象
* */
public static void main(String[] args) {
//1. 创建一个Book对象
Book book = new Book("1002","吃饭歌","吃饭?喝粥?嗦粉?吃面?啃堡?" );
//2. toJSONString()方法
String json = JSON.toJSONString( book );
System.out.println(json);
}
/*
* 使用阿里云FastJson JSON格式的对象 --> Book.class类型对象
* */
public static void main(String[] args) {
//1.转对象 {"id":"1002","info":"吃饭?喝粥?嗦粉?吃面?啃堡?","name":"吃饭歌"}
Book book = JSON.parseObject( "{\"id\":\"1002\",\"info\":\"吃饭?喝粥?嗦粉?吃面?啃堡?\",\"name\":\"吃饭歌\"}", Book.class );
System.out.println(book.getId());
}
/*
* 使用阿里云FastJson JSON格式的数组 --> String.class类型对象
* */
public static void main(String[] args) {
//2.转数组 ["螺蛳粉","酸菜鱼","牛肉面"] parseArray()
List<String> string = JSON.parseArray( "[\"螺蛳粉\",\"酸菜鱼\",\"牛肉面\"]", String.class );
System.out.println(string.get(1));
}
总结
JSON 在给用户发送信息给对象 这一点很重要 !!!
|