本博客java云同桌学习系列,旨在记录本人学习java的过程,并与大家分享,对于想学习java的同学,我希望这个系列能够鼓励大家一同与我学习java,成为“云同桌”。
每月预计保持更新数量三章起,每章都会从整体框架入手,介绍章节所涉及的重要知识点及相关练习题,并会设置推荐学习时间,每篇博客涉及到的点都会在开篇目录进行总览。(博客中所有高亮部分表示是面试题进阶考点)
XML和JSON
学习时间:五天
学习建议:本章以JSON为重点,JSON是当前最主流的数据交互格式,必须掌握解析与生成JSON,掌握之后,自己也能上网找一些API接口下载JSON数据做一些查询天气,查询手机号等等信息的小Demo
1.XML背景
可扩展标记语言,是一种用于标记电子文件使其具有结构性的标记语言。
它可以用来标记数据、定义数据类型,是一种允许用户对自己的标记语言进行定义的源语言。经过长时间发展,程序员们便制定了一种统一的标记语言——xml, 它提供统一的方法来描述和交换独立于应用程序或供应商的结构化数据。是Internet环境中跨平台的、依赖于内容的技术,也是当今处理分布式结构信息的有效工具。
特点:
- 跨平台,跨语言
- 可自定义标记
- 具有自我描述性
应用:
- 进行数据存储
- 可以作为配置文件
- 在网络上进行跨语言数据传输
2.XML基本语法
(1)XML声明语句
规定,在XML文件的第一行需要对自身进行描述
<?xml version="1.0" encoding="UTF-8"?>
(2)标记
XML文档,由一个个的标记组成,标记通常还称为元素,标签,节点
开始标记(开放标记): <标记名称>
结束标记(闭合标记): </标记名称>
-
标记名称: 自定义名称,名称可重复,必须遵循以下命名规则:
1.名称可以含字母、数字以及其他的字符 2.名称不能以数字或者标点符号开始 3.名称不能以字符 “xml”(或者 XML、Xml)开始 4.名称不能包含空格,不能包含冒号(:) 5.名称区分大小写
-
标记内容: 开始标记与结束标记之间 ,是标记的内容.
-
标记层次结构:标记可以嵌套, 但是不允许交叉.根据层次有不同的称呼 (子标记, 父标记 , 兄弟标记, 后代标记 ,祖先标记)
例如:
<persons> <person> <name>李四</name> <length>180cm</length> </person> <person> <name>李四</name> <length>200cm</length> </person> </persons>
-
标记限制:一个XML文档中,有且只能有一个根标记
-
标记属性:标记可以将内部的数据以属性的方式显示
标记中的属性, 在标记开始时 描述, 由属性名和属性值 组成. 格式: 在开始标记中, 描述属性. 可以包含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>
(3)注释
注释不能写在文档文档声明前
注释不能嵌套注释
格式:
注释开始: <!--
注释结束: -->
(4)语法进阶CDATA
CDATA可以将所包含的内容被解析器忽略掉。这样就可以在里面写一些XML不支持的字符内容
使用方式:
<?xml version="1.0" encoding="UTF-8"?>
<Person>
<![CDATA["被忽略掉的字符"]]>
</Person>
3.Java解析XML
<1>解析方式概述
(1)SAX解析
解析方式:事件驱动机制,逐行读取XML文件解析
优点:
1.逐行解析,节省内存
2.不必解析整个文档,可以在某个条件满足时停止解析
3.不必等待所有数据被处理后才开始解析
缺点:
1.单向解析,无法访问同一文档的不同部分
2.无法得知标记的层次,只能维护标记的父子关系
3.只读的解析方式,无法修改xml文档
(2)DOM解析
解析方式:加载整个文档,在内存中建立文档树模型
优点:
1.整个文档加载在内存中,可以对数据和结构进行修改
2.解析是双向的,可以随意在树中解析数据
缺点:整个文档加载在内存中,对于超级大文件来说,消耗资源较大
(3)JDOM解析
解析方式:DOM解析的升级,面向java设计,简化与xml的交互
优点:
1.使用类来操作,简化了DOM的API
2.引入大量java集合类,方便java开发
缺点:
1.灵活性较差
2.性能并不优异
(4)DOM4j解析
解析方式:JDOM的智能分支,支持超出xml基本功能的额外功能,包括Xpath支持,XML Schema支持。
优点:
1.性能优异,功能强大,使用简单
2.软件开发源代码,发展迅速,易推广
<2>DOM4J方式解析XML
步骤:
1. 引入jar文件 dom4j.jar,下载网址:https://dom4j.github.io/
2. 创建一个指向XML文件的输入流
FileInputStream fis = new FileInputStream("xml文件的地址");
3. 创建一个XML读取工具对象
SAXReader sr = new SAXReader();
4. 使用读取工具对象, 读取XML文档的输入流 , 并得到文档对象
Document doc = sr.read(fis);
5. 通过文档对象, 获取XML文档中的根元素对象
Element root = doc.getRootElement();
(1)文档树结构对象Document
模块 java.xml
软件包 org.w3c.dom
Interface Document
介绍:指通过DOM4J解析方式加载到内存中的整个文档的树形结构数据,可以通过其获取该树形结构的节点
常用方法:
修饰 | 名称 | 描述 |
---|---|---|
Element | getRootElement() | 获取此xml文件的根结点对象 |
Element | addElement(String rootName) | 向此xml添加根结点,并设置其名称 |
(2)元素对象Element
模块 java.xml
软件包 org.w3c.dom
Interface Element
介绍:指xml文档树形结构的单独节点
常用方法:
修饰 | 名称 | 描述 |
---|---|---|
String | getName() | 获取元素的名称。 |
Element | getParentElement() | 获取父元素。 |
Element | getElement(int index) | 获取给定索引处的子元素。 |
(3)DOM4J解析网络资源实例
要求,用户输入手机号,将手机号上传至URL资源,取得返回的xml手机相关数据,将数据解析输出
注意:在解析之前,需要导入dom4j的类库
public class Test {
public static void main(String[] args) throws Exception {
//1.获取用户手机号
Scanner scanner = new Scanner(System.in);
System.out.println("请输入要查询的手机号:");
String phone = scanner.nextLine();
//2.找到xml资源获取输入流
URL url = new URL("http://apis.juhe.cn/mobile/get?phone=" + phone + "&dtype=xml&key=9f3923e8f87f1ea50ed4ec8c39cc9253");
URLConnection urlConnection = url.openConnection();
InputStream inputStream = urlConnection.getInputStream();
//3.创建一个XML数据读取对象
SAXReader saxReader = new SAXReader();
//4.获得XML整个数据树结构Document对象
Document document = saxReader.read(inputStream);
//5.获得此树结构数据的根结点
Element root = document.getRootElement();
//6.解析内容
//判断此手机号是否获取到了正确的xml资源
String reason = root.elementText("reason");
if("Return Successd!" .equals(reason)){
//成功获取正确xml资源
Element result = root.element("result");
//省
String province = result.elementText("province");
//市
String city = result.elementText("city");
//运营商
String company = result.elementText("company");
System.out.println("您的手机号码信息如下:");
System.out.println("手机号码归属地为:" + province + city );
System.out.println("手机运营商为:" + company);
}else{
//为获取到正确xml资源
System.out.println("输入的手机号码有误,请重新输入");
main(null);
}
}
}
<3>DOM4J-XPATH解析XML
xml文件中各个结点都可以通过这样xpath路径的方式表示出来,解析时可以利用xpath路径方便的找到存储需要数据的节点
路径表达式:
1. / : 从根节点开始查找
2. // : 从发起查找的节点位置 查找后代节点 ***
3. . : 查找当前节点
4. .. : 查找父节点
5. @ : 选择属性. *
属性使用方式:
[@属性名='值']
[@属性名>'值']
[@属性名<'值']
[@属性名!='值']
books: 路径: //book[@id='1']//name
books
book id=1
name
info
book id=2
name
info
(1)XPATH方式解析手机号运营商实例
public class Test {
public static void main(String[] args) throws Exception {
//1.获取用户手机号
Scanner scanner = new Scanner(System.in);
System.out.println("请输入要查询的手机号:");
String phone = scanner.nextLine();
//2.找到xml资源获取输入流
URL url = new URL("http://apis.juhe.cn/mobile/get?phone=" + phone + "&dtype=xml&key=9f3923e8f87f1ea50ed4ec8c39cc9253");
URLConnection urlConnection = url.openConnection();
InputStream inputStream = urlConnection.getInputStream();
//3.创建一个XML数据读取对象
SAXReader saxReader = new SAXReader();
//4.获得XML整个数据树结构Document对象
Document document = saxReader.read(inputStream);
//5.通过过XPATH获取运营商节点
Node company = document.selectSingleNode("//company");
//6.读取节点内容
System.out.println("您手机号的运营商为:" + company.getText());
}
}
运行截图:
4.JSON语法
JSON(JavaScript Object Notation) JS对象简谱 , 是一种轻量级的数据交换格式.
特点:应用广泛,简单,解析方便速度快
格式:
-
以键值对的方式进行存储,“键名” = “值”
-
一个大括号表示一个对象,括号中描述对象的属性
例如: 一本书 书名 简介 JSON: { "name":"金苹果", "info":"种苹果" }
-
在JSON格式中可以与对象互相嵌套,嵌套键值对数据需要用{},嵌套非键值对需要用数组结构:[元素1,元素2…],解析时数组结构被解析为ArrayList
例如: 一本书 书名 简介 作者 前言 JSON: { "name":"金苹果", "info":{ "author" :"南窗木心", "preface" :"讲述了种金苹果的故事" } }
自06年起,经由谷歌等大厂的推广,JSON迅速发展,占领了大片市场,成为当今主流的跨语言数据交互格式,JSON可能是目前为止学到的未来最经常使用的知识点。
5.Java解析JSON
(1)Gson工具类解析
谷歌公司开发的专门用于JSON进行解析的java类库,项目开源,可以在github上下载Gson的Github的Jar包,建议下载最新版
-
生成JSON
转换JSON字符串的步骤: 1. 引入JAR包 2. 在需要转换JSON字符串的位置编写如下代码即可: String json = new Gson().toJSON(要转换的对象);
public class Test { public static void main(String[] args) throws Exception { //1.建立转化的对象 Book book = new Book("金苹果","讲述种植金苹果的故事"); //2.建立Gson对象 Gson gson = new Gson(); //3.对象转化为JSON String s = gson.toJson(book); //4.打印出来看一下结果 System.out.println(s); /*输出: {"name":"金苹果","info":"讲述种植金苹果的故事"} */ } static class Book{ String name; String info; public Book(String name, String info) { this.name = name; this.info = info; } } }
-
解析JSON
1. 引入JAR包 2. 在需要转换Java对象的位置, 编写如下代码: 对象 = new Gson().fromJson(JSON字符串,对象类型.class);
public class Test { public static void main(String[] args) throws Exception { //1.建立要解析的字符串,注意转义字符 String json = "{\"name\":\"金苹果\",\"info\":\"讲述种植金苹果的故事\"}"; //2.建立Gson对象 Gson gson = new Gson(); //3.JSON转化为对象 Book book = gson.fromJson(json, Book.class); //4.打印出来看一下结果 System.out.println(book.name +","+ book.info); /*输出: 金苹果,讲述种植金苹果的故事 */ } static class Book{ String name; String info; public Book(String name, String info) { this.name = name; this.info = info; } } }
(2)FastJson工具类解析
阿里公司开发的专门用于JSON进行解析的java类库,项目开源,可以在github上下载FastJSON的Github的Jar包,建议下载最新版,在国内比较流行,但有一些bug
-
生成JSON
转换JSON字符串的步骤: 1. 引入JAR包 2. 在需要转换JSON字符串的位置编写如下代码即可: String json=JSON.toJSONString(要转换的对象);
public class Test { public static void main(String[] args) throws Exception { //1.建立要解析的对象 HashMap<String,String> hashMap = new HashMap<>(); hashMap.put("金苹果","讲述种植金苹果的故事"); //2.对象转化为JSON String json = JSON.toJSONString(hashMap); //4.打印出来看一下结果 System.out.println(json); /*输出: {"金苹果":"讲述种植金苹果的故事"} */ } }
-
解析JSON
1. 引入JAR包 2. 在需要转换Java对象的位置, 编写如下代码: 类型 对象名=JSON.parseObject(JSON字符串, 类型.class); 或 List<类型> list=JSON.parseArray(JSON字符串,类型.class);
public class Test { public static void main(String[] args) throws Exception { //1.建立JSON资源 /* 源文件: { "name":"金苹果", "info":[{ "author" : "南窗木心", "preface" : "讲述了种金苹果的故事" }] } */ String json = "{\"name\":\"金苹果\",\"info\":[{\"author\" : \"南窗木心\",\"preface\" : \"讲述了种金苹果的故事\"}]}"; //2.json资源转化为对象 HashMap hashMap = JSON.parseObject(json, HashMap.class); //3.1 取出非数组结构数据看一下 System.out.println(hashMap.get("name")); //3.2 取出数组结构看一下内容和存储结构 System.out.println(hashMap.get("info")); //特别注意,这里需要处理掉左右[] String info = removeFirstAndLast(String.valueOf(hashMap.get("info"))); System.out.println(info); //对info属性再进行一层json解析,输出作者信息 System.out.println(JSON.parseObject(info, HashMap.class).get("author")); /*输出: 金苹果 [{"preface":"讲述了种金苹果的故事","author":"南窗木心"}] {"preface":"讲述了种金苹果的故事","author":"南窗木心"} 南窗木心 */ } //将传入字符串的第一个和最后一个删掉,用于删掉[],来处理成json字符串 public static String removeFirstAndLast(String s) { return s.substring(1,s.length()-1); } }
(3)解析网络天气API的JSON数据实例
要求:用户输入地址后,返回所输地址最近五天的实时天气数据
思想:注册聚合数据的API账号,然后找到获取天气数据的API接口,然后通过URL建立连接,下载下JSON数据,解析JSON数据显示天气
public class Test {
public static void main(String[] args) throws Exception {
//1.获取查询城市
Scanner scanner = new Scanner(System.in);
System.out.println("***欢迎进入南窗木心的天气查询系统***");
System.out.println("请输入要查询天气的城市:");
String cityInput = scanner.nextLine();
//2.获取json资源String对象
URL uRl = new URL("http://apis.juhe.cn/simpleWeather/query?city=" +cityInput+ "&key=a87cbf788ca2f44e9ede00b2e8f45e71");
URLConnection urlConnection = uRl.openConnection();
InputStream inputStream = urlConnection.getInputStream();
String json = new String(inputStream.readAllBytes());
//测试:得到顶层json串(拿字符串对象百度解析出json视图,才能继续解析下去)
//System.out.println(json);
//3.将json转化为集合对象
//3.1 获取object顶层集合
HashMap object = JSON.parseObject(json, HashMap.class);
int error_code = (Integer)object.get("error_code");
//测试:成功返回码
//System.out.println(error_code);
if(0 == error_code){
//3.2 查询到正确的资源后,输出未来五天的气温,天气,风向
//获取result层集合
//测试:result层json串
//System.out.println(String.valueOf(object.get("result")));
HashMap result = JSON.parseObject(String.valueOf(object.get("result")), HashMap.class);
System.out.println("未来五天," +(String) result.get("city")+ "的天气数据如下:" );
//获取future层集合
//测试:future层json串
//System.out.println((String.valueOf(result.get("future"))));
ArrayList future = JSON.parseObject(String.valueOf(result.get("future")), ArrayList.class);
//循环获取每天的天气数据
for(int i = 0;i<5;i++){
//获取这一天的天气
//测试:某一天的天气层数据
//System.out.println(String.valueOf(future.get(i)));
HashMap somedayWeather = JSON.parseObject(String.valueOf(future.get(i)), HashMap.class);
//日期
String data = (String) somedayWeather.get("date");
System.out.print("日期:" + data + "\t");
//最低温度和最高温度
String temperature = String.valueOf(somedayWeather.get("temperature"));
System.out.print("最低温度/最高温度:" + temperature + "\t");
//天气状况
String weather = String.valueOf(somedayWeather.get("weather"));
System.out.print("天气状况:" + weather + "\t\t");
//风向
String direct = String.valueOf(somedayWeather.get("direct"));
System.out.print("风向:" + direct + "\t");
System.out.println();
}
}else{
System.out.println("城市输入错误,请重新输入:");
main(null);
}
//关闭流
inputStream.close();
}
}
//测试API接口:"http://apis.juhe.cn/simpleWeather/query?city=北京&key=a87cbf788ca2f44e9ede00b2e8f45e71"
运行结果:
遇到的问题:
1.对于JSON数据的嵌套中,如果下一层级不是键值对数据,就会使用[],在解析时,[]里面的字符串解析后不能用Map集合接收,因为属于非键值对数据,只有数据没有键,只能用Collection下的list或set等单值集合进行接收
ArrayList future = JSON.parseObject(String.valueOf(result.get("future")), ArrayList.class);
原创不易,都学习都这里了,不妨关注一下或点个赞吧~