文章目录
回顾反射+注解
案例:使用反射+注解技术,完成以下需求
Map集合: Map<String,String>
存储数据:
["stuName"="张三", "stuAge"="22", "stuScore"="88"]
需求:把Map集合中的数据,利用反射+注解,给Student类中的私有属性赋值
Student类
@StuAnnotation(source = "data1")
public class Student {
@StuAnnotation(value="stuName",type = DataTypeEnum.String)
private String name;
@StuAnnotation(value="stuAge",type = DataTypeEnum.Integer)
private int age;
@StuAnnotation(value = "stuScore",type = DataTypeEnum.Double)
private double score;
@Override
public String toString() {
return "Student{" +
"name='" + name + '\'' +
", age=" + age +
", score=" + score +
'}';
}
//无参构造 省略
//全参构造 省略
//getter()、setter() 省略
DataTypeEnum枚举
public enum DataTypeEnum {
String,Integer,Double;
}
StuAnnotation注解
import java.lang.annotation.ElementType;
import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
import java.lang.annotation.Target;
@Target({ElementType.TYPE,ElementType.FIELD})
@Retention(RetentionPolicy.RUNTIME)
public @interface StuAnnotation {
String value() default "";
DataTypeEnum type() default DataTypeEnum.String;
String source() default "";
}
测试类
import java.lang.reflect.Constructor;
import java.lang.reflect.Field;
import java.lang.reflect.InvocationTargetException;
import java.util.HashMap;
import java.util.Map;
public class StuTest {
public static void main(String[] args) throws
NoSuchMethodException, IllegalAccessException, InstantiationException, InvocationTargetException {
//创建Map集合
Map<String, Map<String, String>> data1Map = new HashMap<>();
Map<String, String> map = new HashMap<>();
map.put("stuName", "张三");
map.put("stuAge", "22");
map.put("stuScore","88");//成绩
data1Map.put("data1", map);
method(data1Map);
}
public static void method(Map<String, Map<String, String>> data1Map)
throws NoSuchMethodException, IllegalAccessException,
InvocationTargetException, InstantiationException {
//获取Class对象
Class<Student> studentClass = Student.class;
if (studentClass.isAnnotationPresent(StuAnnotation.class)) {
//获取类上的注解对象
StuAnnotation classAnnotation = studentClass.getAnnotation(StuAnnotation.class);
String key = classAnnotation.source();//key="data1"
Map<String, String> map = data1Map.get(key);
//获取Constructor对象
Constructor<Student> con = studentClass.getConstructor();
Student student = con.newInstance();
//获取Field对象
Field[] fields = studentClass.getDeclaredFields();
for (int i = 0; i < fields.length; i++) {
//获取每一个成员属性对象
Field field = fields[i];
if (field.isAnnotationPresent(StuAnnotation.class)) {
//获取注解对象
StuAnnotation stuAnnotation = field.getAnnotation(StuAnnotation.class);
String name = stuAnnotation.value();//获取注解上的value值
//name="stuAge"
String value = map.get(name);//根据key获取Map集合中的value
//value="22"
//获取注解上的type值
DataTypeEnum type = stuAnnotation.type();
field.setAccessible(true);//去除权限检查
//判断type的枚举值
if (type == DataTypeEnum.String ) {
field.set(student, value);
} else if (type == DataTypeEnum.Integer) {
field.set(student, Integer.parseInt(value));
} else if(type == DataTypeEnum.Double){
field.set(student,Double.parseDouble(value));
}
}
}
System.out.println(student);
}
}
}
一、JDK新特性
1、方法引用
- 能够知道方法引用的四种方式
方法引用概述
class Task implements Runnable{
public void run(){
}
}
Task task = new Task();
new Thread(task).start);
//匿名内部类
new Thread( new Runnable(){
//重写run方法
public void run(){
System.out.println("线程任务");
}
}).start();
//使用Lambda表达式,可以代替匿名内部类 (限制:针对函数式接口)
new Thread( () -> {
System.out.println("线程任务");
}).start();
当使用Lambda实现一个逻辑时,如果这个逻辑已经在某个类中存在相同逻辑的方法,可以直接引用而不需要写Lambda。
结论:Lambda用来简化匿名内部类,方法引用是用来简化Lambda
方法引用的种类
方法引用的符号是双冒号 ::
种类 | 语法格式 |
---|---|
静态方法引用 | 类名::静态方法名 |
构造器引用 | 类名 :: new |
类的任意对象的实例方法引用 | 类名::实例方法 |
2、Base64编码
Base64 编码介绍
Base64 编码是一种常用的字符编码,在很多地方都会用到,他核心作用应该是保证传输数据的正确性,有些网关或系统只能使用ASCII字符
Base64就是用来将非ASCII字符的数据转换成ASCII字符的一种方法,而且base64特别适合在http,mime协议下快速传输数据。
但base64不是安全领域下的加密解密算法。能起到安全作用的效果很差,而且很容易破解
Base64编码表由以下64个字符组成部分:
26个英文字母包含大小写:52
0~9: 10
+ /
: 2
如何将普通的数据转换为Base64数据
编码的规则:把3个字节变成4个字节
原数据: 3 x 8 = 24 bit
目标数护具:24 / 4 = 6 bit (每一个字节上缺少2个bit,使用0补上)例如:
转换前 11111111, 11111111, 11111111 (二进制)
转换后 00111111, 00111111, 00111111, 00111111 (二进制)
转换后的Base64编码,其前两位均为0,我们用一个码表来得到我们想要的字符串(也就是最终的Base64编码)
- 编码:将普通的数据编码成为Base64数据
- 解码:将Base64数据解码成为普通数据
这个普通数据可以是:文本,音频,视频,可以是任何的数据
Base64内嵌类和方法描述
内嵌类
序号 | 内嵌类 & 描述 |
---|---|
1 | static class Base64.Decoder该类实现一个解码器用于,使用 Base64 编码来解码字节数据。 |
2 | static class Base64.Encoder该类实现一个编码器,使用 Base64 编码来编码字节数据 |
方法
序号 | 方法名 & 描述 |
---|---|
1 | **static Base64.Decoder getDecoder()**返回一个 Base64.Decoder ,解码使用基本型 base64 编码方案。 |
2 | **static Base64.Encoder getEncoder()**返回一个 Base64.Encoder ,编码使用基本型 base64 编码方案。 |
3 | **static Base64.Decoder getMimeDecoder()**返回一个 Base64.Decoder ,解码使用 MIME 型 base64 编码方案。 |
4 | **static Base64.Encoder getMimeEncoder()**返回一个 Base64.Encoder ,编码使用 MIME 型 base64 编码方案。 |
5 | **static Base64.Encoder getMimeEncoder(int lineLength, byte[] lineSeparator)**返回一个 Base64.Encoder ,编码使用 MIME 型 base64 编码方案,可以通过参数指定每行的长度及行的分隔符。 |
6 | **static Base64.Decoder getUrlDecoder()**返回一个 Base64.Decoder ,解码使用 URL 和文件名安全型 base64 编码方案。 |
7 | **static Base64.Encoder getUrlEncoder()**返回一个 Base64.Encoder ,编码使用 URL 和文件名安全型 base64 编码方案。 |
**注意:**Base64 类的很多方法从 java.lang.Object 类继承。
代码演示
public static void main(String args[]) {
try {
// 使用基本编码
String base64encodedString = Base64.getEncoder().encodeToString("itheima?java8".getBytes("utf-8"));
System.out.println("Base64 编码字符串 (基本) :" + base64encodedString);
// 解码
byte[] base64decodedBytes = Base64.getDecoder().decode(base64encodedString);
System.out.println("原始字符串: " + new String(base64decodedBytes, "utf-8"));
// URL
base64encodedString = Base64.getUrlEncoder().encodeToString("itheima?java8".getBytes("utf-8"));
System.out.println("Base64 编码字符串 (URL) :" + base64encodedString);
// MIME
StringBuilder stringBuilder = new StringBuilder();
for (int i = 0; i < 10; ++i) {
stringBuilder.append(UUID.randomUUID().toString());
}
byte[] mimeBytes = stringBuilder.toString().getBytes("utf-8");
String mimeEncodedString = Base64.getMimeEncoder().encodeToString(mimeBytes);
System.out.println("Base64 编码字符串 (MIME) :" + mimeEncodedString);
}catch(UnsupportedEncodingException e){
System.out.println("Error :" + e.getMessage());
}
}
二、 XML概述
- 英文:eXtensible Markup Language 可扩展的标记语言,由各种标记(标签,元素)组成。
- 可扩展:所有的标签都是自定义的,可以随意扩展的。如:<abc/>,<姓名>
- 标记语言:整个文档由各种标签组成。清晰,数据结构化!
- XML是通用格式标准,全球所有的技术人员都知道这个东西,都会按照XML的规范存储数据,交互数据!!
1、XML作用
为了存储维护数据
-
数据交换:不同的计算机语言之间,不同的操作系统之间,不同的数据库之间,进行数据交换。
-
配置文件:主要用于各种框架的配置文件。
案例
编写xml文档,用于描述人员信息,person代表一个人员,id是人员的属性代表人员编号。人员信息包括age年龄、name姓名、sex性别信息。
使用Java类去描述:
class Person{
String id;
int age;
String name;
String sex;
}
Person p = new Person("1","张三",18,"男");
编写person.xml文件
<?xml version="1.0" encoding="UTF-8" ?>
<peopel>
<person>
<id>1</id>
<name>张三</name>
<age>18</age>
<sex>男</sex>
</person>
<person>
<id>2</id>
<name>李四</name>
<age>20</age>
<sex>女</sex>
</person>
</peopel>
通过浏览器解析XML的内容
注:XML以后通过Java来进行解析,很少直接在浏览器上显示。
2、XML的组成
- 声明
- 元素(标签)
- 属性
- 注释
- 转义字符【实体字符】
- CDATA 字符区
声明
# 文档声明
<?xml version="1.0" encoding="utf-8" ?>
1. IDEA会自动提示。
2. 文档声明必须为<?xml开头,以?>结束
3. 文档声明必须从文档的1行1列位置开始,==**必须在xml文档中的首行首列**==
4. 文档声明中常见的两个属性:
- version:指定XML文档版本。必须属性,这里一般选择1.0;
- encoding:指定当前文档的编码,可选属性,默认值是utf-8;
元素(标签、标记)
# 元素(标签、标记)
格式1:<person> </person> 有标签体的标签
格式2:<person/> 没有标签体的标签
-
元素是XML文档中最重要的组成部分;
-
普通元素的结构由开始标签、元素体、结束标签组成。【格式1】
-
元素体:元素体可以是元素,也可以是文本,例如:
<person> <name>张三</name> </person>
-
空元素:空元素只有标签,而没有结束标签,但元素必须自己闭合,例如:
<sex/>
-
元素命名
- 区分大小写
- 不能使用空格,不能使用冒号
- 不建议以XML、xml、Xml开头
- 标签名不能数字开头,可以有数字
- 可以使用下划线
可以保持与Java命名标识符一样的规则
-
格式化良好的XML文档,有且仅有一个根元素。
属性
<person id="110">
-
属性是元素的一部分,它必须出现在元素的开始标签中
-
属性的定义格式:
属性名=“属性值”
,其中属性值必须使用单引或双引号括起来 -
一个元素可以有0~N个属性,但一个元素中不能出现同名属性
-
属性名不能使用空格 , 建议不要使用冒号等特殊字符,且必须以字母开头
建议以Java的标识符定义规则做参考
<person id="123">
<name>张三</name>
</person>
注释
<!-- 注释内容 -->
<!--
注释内容 1
注释内容 2
-->
XML的注释与HTML相同,既以<!--
开始,-->
结束。不能嵌套。
Java中注释:
// 单行
/* */ 多行注释
/** */ 文档注释
XML注释:
<!-- 注释内容 -->
<!--<person>注释</person>--> <!-- 快捷键:Ctrl+/ :可以将整行进行注释-->
<person>三生三世</person> <!-- 快捷键:Ctrl+Shift+/:局部注释-->
转义字符[实体字符]
XML中的实体字符与HTML一样。因为很多符号已经被文档结构所使用,所以在元素体或属性值中想使用这些符号就必须使用实体字符
字符 | 预定义的转义字符 | 说明 |
---|---|---|
< | < | 小于(less than) |
> | > | 大于(greater than) |
" | " | 双引号(quotation) |
’ | ' | 单引号(apostrophe) |
& | & | 和号(ampersand ) |
注意:严格地讲,在 XML 中仅有字符 “<“和”&” 是非法的。省略号、引号和大于号是合法的,但是把它们替换为实体引用是个好的习惯。
代码演示
假如在 XML 文档中放置了一个类似 “<” 字符,那么这个文档会产生一个错误,这是因为解析器会把它解释为新元素的开始。因此你不能这样写:
<message>if salary < 1000 then </message>
为了避免此类错误,需要把字符 “<” 替换为实体引用,就像这样:
<message>if salary < 1000 then</message>
字符区(了解)
CDATA (Character Data)字符数据区
当大量的转义字符出现在xml文档中时,会使XML文档的可读性大幅度降低。
这时如果使用CDATA段就会好一些。
<![CDATA[
文本数据 < > & ; " "
]]>
代码演示
<![CDATA[
if salary < 1000 then
]]
CDATA 指的是不应由 XML 解析器进行解析的文本数据(Unparsed Character Data)
CDATA 部分由
<![CDATA[
开始,由]]>
结束快捷模板:CD 回车
注意:
CDATA 部分不能包含字符串 “]]>”。也不允许嵌套的 CDATA 部分。
标记 CDATA 部分结尾的 “]]>” 不能包含空格或折行。
3、 XML约束
DTD约束
在XML技术里,可以编写一个文档来约束一个XML文档的书写规范,这称之为XML约束。
常见的xml约束:DTD、Schema。
注意:我们对于约束的要求是能通过已写好的约束文件编写xml文档.
代码演示:
步骤1:复制bookshelf.dtd文件
步骤2:bookshelf.dtd文件内容如下
<!ELEMENT 书架 (书+)>
<!ELEMENT 书 (书名,作者,售价)><!--约束元素书的子元素必须为书名、作者、售价-->
<!ELEMENT 书名 (#PCDATA)>
<!ELEMENT 作者 (#PCDATA)>
<!ELEMENT 售价 (#PCDATA)>
步骤三:新建books.xml,代码如下
引用 <!DOCTYPE 根元素 SYSTEM "dtd约束文件的路径">
<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE 书架 SYSTEM "bookshelf.dtd"><!--指定使用bookshelf.dtd文件约束当前xml文档-->
<书架>
<书>
<书名>JavaWeb开发教程</书名>
<作者>张孝祥</作者>
<售价>100.00元</售价>
</书>
<书>
<书名>三国演义</书名>
<作者>罗贯中</作者>
<售价>100.00元</售价>
<测试>hello</测试><!--不符合约束,书的子元素必须为书名、作者、售价-->
</书>
</书架>
步骤四:idea开发工具books.xml的dtd约束验证不通过的效果
当编写xml文档时不符合指定dtd约束时,进行提示xml编写错误,如下图:
在企业实际开发中,很少自己编写DTD约束文档,通常情况下通过框架提供的DTD约束文档编写对应的XML文档。所以这一知识点的要求是可以根据DTD约束文档内容编写XML文档。
Schema约束
Schema 语言也也叫做 XSD(XML Schema Definition)。
其本身也是XML格式文档,但Schema文档扩展名为xsd,而不是xml。
Schema 功能更强大,数据类型约束更完善。 比DTD强大,是DTD代替者。
代码演示:
步骤1:复制schema约束文件bookshelf.xsd,其中已对售价约束了数据类型,代码如下
<?xml version="1.0" encoding="UTF-8" ?>
<!--
传智播客schema教学实例文档.将注释中的以下内容复制到要编写的xml的声明下面
复制内容如下:
<书架 xmlns="http://www.itcast.cn"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://www.itcast.cn bookshelf.xsd"
>
-->
<xs:schema xmlns:xs="http://www.w3.org/2001/XMLSchema"
targetNamespace="http://www.itcast.cn"
elementFormDefault="qualified">
<xs:element name='书架' >
<xs:complexType>
<xs:sequence maxOccurs='unbounded' >
<xs:element name='书' >
<xs:complexType>
<xs:sequence>
<xs:element name='书名' type='xs:string' />
<xs:element name='作者' type='xs:string' />
<xs:element name='售价' type='xs:double' />
</xs:sequence>
</xs:complexType>
</xs:element>
</xs:sequence>
</xs:complexType>
</xs:element>
</xs:schema>
步骤2:新建books2.xml使用schema约束文件bookshelf.xsd,代码如下
<?xml version="1.0" encoding="UTF-8"?>
<书架
xmlns="http://www.itcast.cn"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://www.itcast.cn bookshelf.xsd"
><!--指定schema文档约束当前XML文档-->
<书>
<书名>JavaScript网页开发</书名>
<作者>张孝祥</作者>
<售价>abc</售价>
</书>
</书架>
步骤3:schema约束XML文档中对元素体数据类型的约束,开发工具提示效果
对比,DTD约束无法对具体数据类型进行约束,所以开发工具没有任何错误提示
虽然schema功能比dtd强大,但是编写要比DTD复杂,同样以后我们在企业开发中也很少会自己编写schema文件。
xml编写与约束内容已经完成了,根据xml的作用我们了解到,无论是xml作为配置文件还是数据传输,我们的程序都要获取xml文档中的数据以便我们进行具体的业务操作,接下来我们使用XML解析技术Dom4j获取xml文档中的数据。
4、名称空间
名称空间就是用来处理元素和属性的名称冲突问题,与Java中的包是同一用途
名称空间就在在根元素后面的内容 , 使用xmlns到引入约束
一个XML文档最多可以使用一个DTD文件,但一个XML文档中使用多个Schema文件,若这些Schema文件中定义了相同名称的元素时,使用的时候就会出现名字冲突。
这就像一个Java文件中使用了
import java.util.*
和import java.sql.*
时,在使用Date类时,那么就不明确Date是哪个包下的Date了。同理 , 在XML文档中就需要通过名称空间(namespace)来区分元素和属性是来源于哪个约束中的。
当一个XML文档中需要使用多个Schema文件的时候 , 有且仅有一个使用缺省的 , 其他的名称空间都需要起别名 。
参考资料中的 applicationContext.xml文件(spring框架的配置文件)
xmlns="http://www.itcast.cn"
<!-- 缺省的名称空间.使用此约束中的元素的时候只需要写元素名即可 例如:<书></书> -->
xmlns:aa="http://java.sun.com"
<!-- aa就是此约束的别名,使用此约束中的元素的时候就需要加上别名 例如:<aa:书></aa:书> -->
schemaLocation:指定命名空间所在的文件
命名空间在约束文件的:targetNamespace中
引入xsd 文档
<?xml version="1.0" encoding="UTF-8" ?>
<根元素 xmlns="命名空间"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="命名空间 文件路径"
>
</根元素>
三、Dom4j解析
1、XML解析
当将数据存储在XML后,我们就希望通过程序获取XML的内容。
我们使用Java基础所学的IO知识是可以完成的,不过需要非常繁琐的操作才可以完成,且开发中会遇到不同问题(只读、读写)。
人们为不同问题提供不同的解析方式,使用不同的解析器进行解析,方便开发人员操XML。
2、 解析方式和解析器
开发中比较常见的解析方式有三种,如下:
- DOM:要求解析器把整个XML文档装载到内存,并解析成一个Document对象
a)优点:元素与元素之间保留结构关系,故可以进行增删改查操作。
b)缺点:XML文档过大,可能出现内存溢出
- SAX:是一种速度更快,更有效的方法。它逐行扫描文档,一边扫描一边解析。并以事件驱动的方式进行具体解析,每执行一行,都触发对应的事件。
a)优点:处理速度快,可以处理大文件
b)缺点:只能读,逐行后将释放资源,解析操作繁琐。
- PULL:Android内置的XML解析方式,类似SAX。(了解)
解析器,就是根据不同的解析方式提供具体实现。
有的解析器操作过于繁琐,为了方便开发人员,有提供易于操作的解析开发包
3、 Dom4j的基本使用
解析原理
将整个XML文档加载到内存,生成一个DOM树,并获得一个Document对象,
通过Document对象就可以对DOM树进行操作。以下面books.xml文档为例。
<?xml version="1.0" encoding="UTF-8"?>
<books>
<book id="0001">
<name>JavaWeb开发教程</name>
<author>张孝祥</author>
<sale>100.00元</sale>
</book>
<book id="0002">
<name>三国演义</name>
<author>罗贯中</author>
<sale>100.00元</sale>
</book>
</books>
结构模型
DOM中的核心概念就是节点,在XML文档中的元素、属性、文本,在DOM中都是节点!
所有的节点都封装到了Document对象中。
导入依赖的库(引入dom4j的jar包)
官网下载 zip 包。http://www.dom4j.org/
库导入方式:
在IDEA中,选择项目鼠标右键—>弹出菜单–>open Module settings”–>Dependencies–>±->JARs or directories… 找到dom4j-1.6.1.jar,成功添加之后点击"OK" 即可。
直接右键选择:Add as Library
4、Dom4j 常用的方法
dom4j 必须使用核心类SaxReader加载xml文档获得Document,
通过Document对象获得文档的根元素,然后就可以进行操作了。
SAXReader对象
方法 | 作用 |
---|---|
SAXReader sr = new SAXReader(); | 构造器 |
Document read(String url) | 加载执行xml文档 |
Document对象
方法 | 作用 |
---|---|
Element getRootElement() | 获得根元素 |
Element对象
方法 | 作用 |
---|---|
List<Element> elements(String ele ) | 获得指定名称的所有子元素。可以不指定名称 |
Element element(String ele) | 获得指定名称第一个子元素。 |
String getName() | 获得当前元素的元素名 |
String attributeValue(String attrName) | 获得指定属性名的属性值 |
String elementText(Sting ele) | 获得指定名称子元素的文本值 |
String getText() | 获得当前元素的文本内容 |
5、代码演示
创建books.xml
<?xml version="1.0" encoding="UTF-8"?>
<books>
<book id="0001">
<name>JavaWeb开发教程</name>
<author>张孝祥</author>
<sale>100.00元</sale>
</book>
<book id="0002">
<name>三国演义</name>
<author>罗贯中</author>
<sale>100.00元</sale>
</book>
</books>
解析此文件,获取每本书的id值,以及书本名称,作者名称和价格.
步骤分析:
- 创建一个SaxReader对象,调用read方法加载一个xml文件获得文档对象
- 通过文档对象,获取根元素
- 通过根元素一层一层的进行解析子元素。
import org.dom4j.Document;
import org.dom4j.DocumentException;
import org.dom4j.Element;
import org.dom4j.io.SAXReader;
import java.util.List;
public class Demo01 {
public static void main(String[] args) throws DocumentException {
//1. 创建一个SaxReader对象,调用read方法加载一个xml文件获得文档对象
SAXReader sr = new SAXReader();
Document doc = sr.read("day15/xml/book.xml");
//2. 通过文档对象,获取根元素
Element rootElement = doc.getRootElement();
//3. 通过根元素一层一层的进行解析子元素。
//获取所有的子元素
List<Element> bookElements = rootElement.elements("book");
for (Element bookElement : bookElements) {
//System.out.println(bookElement);
//解析属性
String id = bookElement.attributeValue("id");
System.out.println("id = " + id);
//获取子元素文本
String name = bookElement.elementText("name");
String author = bookElement.elementText("author");
String sale = bookElement.elementText("sale");
System.out.println("name = " + name);
System.out.println("author = " + author);
System.out.println("sale = " + sale);
System.out.println("----------------------");
}
}
}
四、XPath解析
1、XPath解析基本概述
XPath使用路径表达式来选取XML/HTML 文档中的元素节点或属性节点。
节点是通过沿着路径 (path) 来选取的。
XPath在解析XML/HTML文档方面提供了独树一帜的路径思想
XPath使用步骤
步骤1:导入jar包(dom4j和jaxen-1.1-beta-6.jar)
步骤2:通过dom4j的SaxReader获取Document对象
步骤3: 利用Xpath提供的api,结合xpath的语法完成选取XML文档元素节点进行解析操作
XPath常用API
借助dom4j实现,在dom4j中有Node类型,而Document,Element都是Node的子类型,
所以可以使用Node中的方法。
Node接口中存在以下方法
方法 | 作用 |
---|---|
List<Element> selectNodes("路径表达式") | 获取符合表达式的元素集合 |
Element selectSingleNode("路径表达式") | 获取符合表达式的唯一元素 |
XPath表达式语法
XPath表达式,就是用于选取XML文档中节点的表达式字符串
获取XML文档节点元素一共有如下4种XPath语法方式:
- 绝对路径表达式方式 例如: /元素/子元素/子子元素…
- 相对路径表达式方式 例如: 子元素/子子元素… 或者 ./子元素/子子元素…
- 全文搜索路径表达式方式 例如: //子元素//子子元素
- 谓语(条件筛选)方式 例如:/元素/子元素[@id]
2、XPath解析XML案例
XPath绝对路径
格式:
String xpath="/根元素/子元素/子子元素...";
绝对路径是以"/"开头,一级一级的描述标签的层级路径就是绝对路径
(这里注意不可以跨层级)
需求:将素材中的Contact.xml拷贝到项目中,采用绝对路径获取从根节点开始逐层的查找name节点列表并打印信息
步骤:
- 先创建SAXReader对象,调用read方法,将Contact.xml关联,得到Document对象
- 定义绝对路径
- 调用selectedNodes方法
代码实践:
String path="/contactList/contact/name";
public class Demo01 {
public static void main(String[] args) throws DocumentException {
//1. 先创建SAXReader对象,调用read方法,将Contact.xml关联,得到Document对象
SAXReader sr = new SAXReader();
Document doc = sr.read("day16/xml/Contact.xml");
//2. 定义绝对路径
String xpath = "/contactList/contact/name";
//3. 调用selectedNodes
List<Node> nodes = doc.selectNodes(xpath);
for (Node node : nodes) {
String text = node.getText();
System.out.println("text = " + text);
}
}
}
//打印结果:
text = 潘金莲
text = 武松
text = 武大郎
XPath相对路径表达式
格式:
String xpath2="./子元素/子子元素"; // "./"代表当前元素路径位置
需求:先采用绝对路径获取contact 节点,再采用相对路径获取下一级name子节点并打印信息
String path1="/contactList/contact";//绝对路径
String path2="./name"; //参照路径:contact
代码实践:
public class Demo02 {
public static void main(String[] args) throws DocumentException {
//需求:先采用绝对路径获取 contact
// 节点 再采用相对路径获取下一级name子节点并打印信息。
//1. 先创建SAXReader对象,调用read方法,将Contact.xml关联,得到Document对象
SAXReader sr = new SAXReader();
Document doc = sr.read("day16/xml/Contact.xml");
//2. 定义绝对路径
String xpath = "/contactList/contact";
//3. 调用selectedNodes
List<Node> nodes = doc.selectNodes(xpath);
for (Node node : nodes) {//contact
Node name = node.selectSingleNode("./name");
System.out.println("name.getText() = " + name.getText());
}
}
}
//打印结果:
name.getText() = 潘金莲
name.getText() = 武松
name.getText() = 武大郎
XPath全文搜索路径表达式
格式:
String xpath1="//子元素//子子元素";
“/”符号,代表逐级写路径
“//”符号,不用逐级写路径,可以直接选取到对应的节点,是全文搜索匹配的不需要按照逐层级
举例 | 说明 |
---|---|
//contact | 找contact元素,无论元素在哪里 |
//contact/name | 找contact,无论在哪一级,但name一定是contact的子节点 |
//contact//name | contact无论在哪一种,name只要是contact的子孙元素都可以找到 |
需求:直接全文搜索所有的 name元素并打印
String xpath="//name";
代码实践:
public class Demo03 {
public static void main(String[] args) throws DocumentException {
//直接全文搜索所有的 name元素并打印
//1. 先创建SAXReader对象,调用read方法,将Contact.xml关联,得到Document对象
SAXReader sr = new SAXReader();
Document doc = sr.read("day16/xml/Contact.xml");
//2. 定义绝对路径
String xpath = "//name";
//3. 调用selectedNodes
List<Node> nodes = doc.selectNodes(xpath);
for (Node node : nodes) {//name
System.out.println("node.getText() = " + node.getText());
}
}
}
谓语(条件筛选)方式
谓语,又称为条件筛选方式,就是根据条件过滤判断进行选取节点
格式:
String xpath1="//元素[@属性名]";//查找元素对象,全文中只要含有该属性名的元素
String xpath2="//元素[@属性名=value]";//查找元素对象,全文中只要含有该属性,并指定的值
需求:查找含有id属性的contact元素
String xpaht ="//contact[@id]";
public class Demo04 {
public static void main(String[] args) throws DocumentException {
//查找含有id属性的contact元素
//1. 先创建SAXReader对象,调用read方法,将Contact.xml关联,得到Document对象
SAXReader sr = new SAXReader();
Document doc = sr.read("day16/xml/Contact.xml");
//2. 定义绝对路径
String xpath = "//contact[@id]";
//3. 调用selectedNodes
List<Node> nodes = doc.selectNodes(xpath);
for (Node node : nodes) {//name
String name = node.getName();
System.out.println("name = " + name);
Element con = (Element) node;
System.out.println("con.attributeValue(\"id\") = " + con.attributeValue("id"));
}
}
}