学习目标
一.XML 概述
1 概念
XML(Extensible Markup Language):可扩展标记语言
可扩展:标签都是自定义的。
2 发展历程
HTML 和 XML 都是 W3C(万维网联盟)制定的标准,最开始 HTML 的语法过于松散,于是 W3C 制定了更严格的 XML 语法标准,希望能取代 HTML。但是程序员和浏览器厂商
并不喜欢使用 XML,于是现在的 XML 更多的用于配置文件及传输数据等功能。
配置文件
:在今后的开发过程当中我们会频繁使用框架(框架:半成品软件),使用框架时,需要写配置文件配置相关的参数,让框架满足我们的开发需求。而我们写的配置文件
中就有一种文件类型是 XML。
传输数据
:在网络中传输数据时并不能传输 java 对象,所以我们需要将 JAVA 对象转成字符串传输,其中一种方式就是将对象转为 XML 类型的字符串。
3 xml 和 html 的区别:
- xml 语法严格,html 语法松散
- xml 标签自定义,html 标签预定义
4 XML 基本语法
- 文件后缀名是.xml
- 第一行必须是文档声明
- 有且仅有一个根标签
- 属性值必须用引号(单双都可)引起来
- 标签必须正确关闭
- 标签名区分大小写
5 XML 组成部分
5.1 文档声明
文档声明必须放在第一行,格式为:<?xml 属性列表 ?>
属性列表:
version:版本号(必须)
encoding:编码方式 (不写时默认是utf-8编码)
5.2 标签:
XML 中标签名是自定义的,标签名有以下要求:
- 包含数字、字母、其他字符 (啥字符都行)
- 不能以数字和标点符号(下划线和$除外)开头
- 不能包含空格
5.3 指令(了解)
指令是结合 css 使用的,但现在 XML 一般不结合 CSS,语法为:
<?xml-stylesheet type="text/css" href="a.css" ?>
5.4 属性
属性值必须用引号(单双都可)引起来
5.5 文本
如果想原样展示文本,需要设置 CDATA 区,格式为:<![CDATA[想原样展示的文本]]>
二.约束
1.什么是约束
约束是一个文件,可以规定 xml 文档的书写规则。
我们作为框架的使用者,不需要会写约束文件,只要能够在 xml 中引入约束文档,简单的读懂约束文档即可。
XML 有两种约
束文件类型:DTD 和 Schema。
2.DTD 约束
DTD 是一种较简单的约束技术
引入:
本地:<!DOCTYPE 根标签名 SYSTEM "dtd 文件的位置">
网络:<!DOCTYPE 根标签名 PUBLIC "dtd 文件的位置" "dtd 文件路径">
示例:
student.dtd:
<!ELEMENT students (student*) >
<!ELEMENT student (name,age,sex)>
<!ELEMENT name (#PCDATA)>
<!ELEMENT age (#PCDATA)>
<!ELEMENT sex (#PCDATA)>
<!ATTLIST student number ID #REQUIRED>
解释:
<!ELEMENT students (student*) >
*代表多个,一个students结点下面有多个student结点,ELEMENT放在最上面代表students是根结点
<!ELEMENT student (name,age,sex)>
一个student结点下可以放一个name结点,一个age结点,一个sex结点,且按此顺序不能乱!
<!ELEMENT name (#PCDATA)>
PCDATA是文本的意思,即name结点里放的是文本,下面的age,sex同理
<!ELEMENT age (#PCDATA)>
<!ELEMENT sex (#PCDATA)>
<!ATTLIST student number ID #REQUIRED>
student结点有个ID类型的number属性 ,且ID不能重复,#REQUIRED代表必须。
按照如上约束写的student.xml:
<?xml version="1.0" encoding="utf-8" ?>
<!DOCTYPE students SYSTEM "student.dtd">
<students>
<student number="baizhan001">
<name>懒羊羊</name>
<age>10</age>
<sex>男</sex>
</student>
<student number="baizhan002">
<name>美羊羊</name>
<age>8</age>
<sex>女</sex>
</student>
</students>
3.Schema 约束
DTD约束不常用,而Schema(xsd)比较常用。
引入:
(1)写 xml 文档的根标签
(2)引入 xsi 前缀:确定 Schema 文件的版本。
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
(3)引入 Schema 文件
xsi:schemaLocation="Schema 文件定义的命名空间 Schema 文件的具体路径"
(4)为 Schema 约束的标签声明前缀
xmlns:前缀="Schema 文件定义的命名空间"
例如:
xsd文件本质上也是一个xml文件,即
Schema 约束就是用一个xml文件约束另一个xml文件。
enumeration是枚举类型,意思是只有那几个枚举选项可以选择。
\d是数字的意思,所以\d{4}是四位是四位数字的意思。
targetNamespace是域名空间。?
student.xsd:
<?xml version="1.0"?>
<xsd:schema xmlns="http://www.itbaizhan.cn/xml"
xmlns:xsd="http://www.w3.org/2001/XMLSchema"
targetNamespace="http://www.itbaizhan.cn/xml" elementFormDefault="qualified">
<!--students标签-->
<xsd:element name="students" type="studentsType"/>
<xsd:complexType name="studentsType">
<xsd:sequence>
<!--student标签,students下的student标签最少有0个,最多无上限-->
<xsd:element name="student" type="studentType" minOccurs="0" maxOccurs="unbounded"/>
</xsd:sequence>
</xsd:complexType>
<xsd:complexType name="studentType">
<xsd:sequence>
<!--student下又有三个标签,分别是name,age,sex-->
<xsd:element name="name" type="xsd:string"/>
<xsd:element name="age" type="ageType" />
<xsd:element name="sex" type="sexType" />
</xsd:sequence>
<!--student下又有一个number属性,是必须的-->
<xsd:attribute name="number" type="numberType" use="required"/>
</xsd:complexType>
<!--对sexType类型的约束-->
<xsd:simpleType name="sexType">
<!--是个字符串-->
<xsd:restriction base="xsd:string">
<!--枚举类型,要么是male,要么是female-->
<xsd:enumeration value="male"/>
<xsd:enumeration value="female"/>
</xsd:restriction>
</xsd:simpleType>
<!--对ageType类型的约束-->
<xsd:simpleType name="ageType">
<!--是个整数-->
<xsd:restriction base="xsd:integer">
<!--最小值是0,最大值是256-->
<xsd:minInclusive value="0"/>
<xsd:maxInclusive value="256"/>
</xsd:restriction>
</xsd:simpleType>
<!--对numberType类型的约束-->
<xsd:simpleType name="numberType">
<!--是个字符串-->
<xsd:restriction base="xsd:string">
<!--4位整数-->
<xsd:pattern value="baizhan_\d{4}"/>
</xsd:restriction>
</xsd:simpleType>
</xsd:schema>
按照如上约束写的student.xml:
<?xml version="1.0"?>
<a:students
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://www.itbaizhan.cn/xml student.xsd"
xmlns:a="http://www.itbaizhan.cn/xml">
<!--前缀的作用就是当配置文件多了,前缀可以解决标签重名的问题-->
<a:student number="baizhan_0001">
<a:name>喜羊羊</a:name>
<a:age>10</a:age>
<a:sex>male</a:sex>
</a:student>
</a:students>
三.XML解析
1.XML 解析思想?
XML 解析即读写 XML 文档中(我们想提取)的数据。框架的开发者通过 XML 解析读取框架使用者配置的参数信息,开发者也可以通过 XML 解析读取网络传来的数据。
DOM:将标记语言文档一次性加载进内存,在内存中形成一颗 dom 树
- 优点:操作方便,可以对文档进行 CRUD (增删改查)的所有操作
- 缺点:占内存
SAX:逐行读取,基于事件驱动的。
- 优点:不占内存,一般用于手机 APP 开发中读取 XML
- 缺点:只能读取,不能增删改
?Java开发中DOM用的比较多,SAX在手机APP中用的比较多。
DOM比较占内存,因为每个结点都要的生成一个Java对象;而SAX是一行一行读取,故只存一行的数据对象,所以不占内存。
2 常见解析器
JAXP:SUN 公司提供的解析器,支持 DOM 和 SAX 两种思想
DOM4J:一款非常优秀的解析器 ,主要支持DOM思想
Jsoup:
Jsoup 是一款 Java 的 HTML 解析器,可直接解析某个 URL 地址、HTML 文本内容。它提供了一套非常省力的 API,可通过 DOM,CSS 以及类似于 jQuery 的操作方
法来取出和操作数据。
PULL:Android 操作系统内置的解析器,支持 SAX 思想
2.Jsoup 解析器
(1)快速入门
步骤:
(1) 导入 jar 包
在工程下新建一个lib目录,将jsoup-1.11.2.jar放进去,右键Add as Library,然后
Level选择Module Library
(2) 加载 XML 文档进内存,获取 DOM 树对象 Document
(3) 获取对应的标签 Element 对象
(4) 获取数据
bug:
获取绝地路径时遇到的一个bug,报了找不到系统指定文件的异常,我看了下我的路径中有个文件名称是Idea 2019,而中间的空格却被解析成了%20
解决办法,参考这篇文章
import org.jsoup.Jsoup;
import org.jsoup.nodes.Document;
import org.jsoup.nodes.Element;
import org.jsoup.select.Elements;
import java.io.File;
import java.io.IOException;
public class Demo1 {
//获取XML中所有的学生姓名
public static void main(String[] args) throws IOException {
/*
(2) 加载 XML 文档进内存,获取 DOM 树对象 Document
2.1找到XML文档的绝对路径
利用类加载器,通过项目中文件的相对路径找到硬盘中的绝对路径
*/
//类加载器
ClassLoader classLoader=Demo1.class.getClassLoader();
//获得绝对路径
//用replace将因路径中有空格而出现的%20还原为原来的空格
String path=classLoader.getResource("com/baizhan/xml/xsd/student.xml").getPath().replace("%20"," ");
//System.out.println(path);
//2.2根据XML文档的路径,把XML文档加载进内存,并解析成Dom树对象
Document document= Jsoup.parse(new File(path),"utf-8");
//输出的文件内容是html文档,因为jsoup最开始是解析html文档的,所以解析式把document对象封装成html文档
//System.out.println(document);
/*
(3) 获取对应的标签 Element 对象
方法和js差不多
*/
//Elements是Element的一个集合
//根据标签名获得标签时,加了前缀不要忘记写前缀
Elements name=document.getElementsByTag("a:name");
//(4) 获取数据
for (Element element:name){
String text=element.text();
System.out.println(text);
}
}
}
(2)常用对象
Jsoup:
解析 xml 或 html,形成 dom 树对象。
常用方法:
一个解析方法,三个重载
static Document parse(File in, String charsetName):解析本地文件
static Document parse(String html):解析 html 或 xml 字符串
static Document parse(URL url, int timeoutMillis):解析网页源文件
import org.jsoup.Jsoup;
import org.jsoup.nodes.Document;
import java.io.File;
import java.io.IOException;
import java.net.URL;
public class Demo2 {
public static void main(String[] args) throws IOException {
//解析本地文件
//获得绝对路径
// String path=Demo2.class.getClassLoader().getResource(
// "com/baizhan/xml/xsd/student.xsd").getPath().replace("%20"," ");
// Document document= Jsoup.parse(new File(path),"utf-8");
// System.out.println(document);
//解析字符串
// Document document1=Jsoup.parse("<a:student number=\"baizhan_0001\">\n" +
// " <a:name>喜羊羊</a:name>\n" +
// " <a:age>10</a:age>\n" +
// " <a:sex>male</a:sex>\n" +
// " </a:student>\n" +
// " <a:student number=\"baizhan_0002\">\n" +
// " <a:name>美羊羊</a:name>\n" +
// " <a:age>15</a:age>\n" +
// " <a:sex>female</a:sex>\n" +
// " </a:student>");
// System.out.println(document1);
//解析网络资源
//第一个参数是访问的网络地址,第二个参数是最大等待时间,超过这个时间就默认是访问超时
Document document=Jsoup.parse(new URL("http://www.baidu.com"),5000);//5s
System.out.println(document);
}
}
Document:xml 的 dom 树对象
常用方法:
Element getElementById(String id):根据 id 获取元素
Elements getElementsByTag(String tagName):根据标签名获取元素
Elements getElementsByAttribute(String key):根据属性获取元素
Elements getElementsByAttributeValue(String key,String value):根据属性名=属性值获取元素。
Elements select(Sting cssQuery):根据选择器选取元素。
student.xml:
<?xml version="1.0" encoding="UTF-8" ?>
<students>
<student number="baizhan_0001">
<name>喜羊羊</name>
<age id="a1">10</age>
<sex class="hh">male</sex>
</student>
<student number="baizhan_0002">
<name>美羊羊</name>
<age>8</age>
<sex>female</sex>
</student>
</students>
Demo3.java :
import org.jsoup.Jsoup;
import org.jsoup.nodes.Document;
import org.jsoup.nodes.Element;
import org.jsoup.select.Elements;
import java.io.File;
import java.io.IOException;
public class Demo3 {
public static void main(String[] args) throws IOException {
String path=Demo3.class.getClassLoader().getResource(
"com/baizhan/xml/jsoup/student.xml").getPath().replace("%20"," ");
Document document= Jsoup.parse(new File(path),"utf-8");
//根据 id 获取元素
Element element1=document.getElementById("a1");
System.out.println(element1.text());
System.out.println("-----------------------");
//根据标签名获取元素
Elements elements=document.getElementsByTag("age");
for (Element element:elements){
System.out.println(element.text());
}
System.out.println("-----------------------");
//根据属性获取元素
Elements elements1=document.getElementsByAttribute("number");
for (Element element:elements1){
System.out.println(element);
}
System.out.println("-----------------------");
//根据属性名 =属性值获取元素
Elements elements2=document.getElementsByAttributeValue("number","baizhan_0001");
for (Element element:elements2){
System.out.println(element);
}
System.out.println("------------------------------------------");
//根据选择器选取元素(速度最快)
//css中根据id来选
Elements elements3=document.select("#a1");
//text()就是标签内的值
System.out.println(elements3.text());
System.out.println("-----------------------");
//css中根据class来选
Elements elements4=document.select(".hh");
System.out.println(elements4);
System.out.println("-----------------------");
//css中根据标签名来选
Elements elements5=document.select("name");
System.out.println(elements5);
}
}
Element: 元素对象
常用方法:
String text():获取元素包含的纯文本。
String html():获取元素包含的带标签的文本。
String attr(String attributeKey):获取元素的属性值。?
import org.jsoup.Jsoup;
import org.jsoup.nodes.Document;
import org.jsoup.nodes.Element;
import org.jsoup.select.Elements;
import java.io.File;
import java.io.IOException;
public class Demo4 {
public static void main(String[] args) throws IOException {
String path=Demo4.class.getClassLoader().getResource(
"com/baizhan/xml/jsoup/student.xml").getPath().replace("%20"," ");
Document document= Jsoup.parse(new File(path),"utf-8");
Elements elements=document.getElementsByAttributeValue("number","baizhan_0001");
for (Element element:elements){
//获取元素包含的纯文本
System.out.println(element.text());
System.out.println("------------------------");
//获取元素包含的带标签的文本
System.out.println(element.html());
System.out.println("------------------------");
//获取元素的属性值。
System.out.println(element.attr("number"));
}
}
}
3 XPath 解析
XPath 即为 XML 路径语言,它是一种用来确定标记语言文档中某部分位置的语言。
使用方法:
1. 导入 Xpath 的 jar 包
将JsoupXpath-0.3.2.jar放进去,右键Add as Library,然后Level选择Module Library
2. 获取 Document 对象
3. 将 Document 对象转为 JXDocument 对象
4. JXDocument 调用 selN(String xpath),获取 List<JXNode>对象。
5. 遍历 List<JXNode>,调用 JXNode 的 getElement(),转为 Element 对象。
6. 处理 Element 对象。
?
import cn.wanghaomiao.xpath.exception.XpathSyntaxErrorException;
import cn.wanghaomiao.xpath.model.JXDocument;
import cn.wanghaomiao.xpath.model.JXNode;
import org.jsoup.Jsoup;
import org.jsoup.nodes.Document;
import org.jsoup.nodes.Element;
import java.io.File;
import java.io.IOException;
import java.util.List;
public class XPathDemo {
public static void main(String[] args) throws IOException, XpathSyntaxErrorException {
//2. 获取 Document 对象
String path=XPathDemo.class.getClassLoader().getResource(
"com/baizhan/xml/jsoup/student.xml").getPath().replace("%20"," ");
Document document= Jsoup.parse(new File(path),"utf-8");
// 3. 将 Document 对象转为 JXDocument 对象
JXDocument jxDocument=new JXDocument(document);
// 4. cn.wanghaomiao.xpath.model.JXDocument 调用 selN(String xpath),获取 List<JXNode>对象。
//获取所有的name标签,XPath的具体规则去W3C上去看
//List<JXNode> jxNodes=jxDocument.selN("//name");
//找到属性number为baizhan_0002的student的标签元素
//List<JXNode> jxNodes=jxDocument.selN("//student[@number='baizhan_0002']");
//想拿到baizhan_0001的年龄,找到属性number为baizhan_0001的student的标签元素下的age标签
List<JXNode> jxNodes=jxDocument.selN("//student[@number='baizhan_0001']/age");
// 5. 遍历 List<JXNode>,调用 JXNode 的 getElement(),转为 Element 对象。
for (JXNode jxNode:jxNodes){
Element element=jxNode.getElement();
// 6. 处理 Element 对象。
System.out.println(element.text());
}
}
}
|