15-JavaSE【方法引用、Base64、XML,Dom4j】

回顾反射+注解

案例:使用反射+注解技术,完成以下需求

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内嵌类和方法描述

内嵌类

序号内嵌类 & 描述
1static class Base64.Decoder该类实现一个解码器用于,使用 Base64 编码来解码字节数据。
2static 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概述

  1. 英文:eXtensible Markup Language 可扩展的标记语言,由各种标记(标签,元素)组成。
  2. 可扩展:所有的标签都是自定义的,可以随意扩展的。如:<abc/>,<姓名>
  3. 标记语言:整个文档由各种标签组成。清晰,数据结构化!
  4. XML是通用格式标准,全球所有的技术人员都知道这个东西,都会按照XML的规范存储数据,交互数据!!
1、XML作用

为了存储维护数据

  1. 数据交换:不同的计算机语言之间,不同的操作系统之间,不同的数据库之间,进行数据交换。
    在这里插入图片描述

  2. 配置文件:主要用于各种框架的配置文件。

案例

编写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的组成
  1. 声明
  2. 元素(标签)
  3. 属性
  4. 注释
  5. 转义字符【实体字符】
  6. 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/>  没有标签体的标签
  1. 元素是XML文档中最重要的组成部分;

  2. 普通元素的结构由开始标签、元素体、结束标签组成。【格式1】

  3. 元素体:元素体可以是元素,也可以是文本,例如:

    <person> 
      <name>张三</name> 
    </person>
    
  4. 空元素:空元素只有标签,而没有结束标签,但元素必须自己闭合,例如:

    <sex/>
    
  5. 元素命名

    • 区分大小写
    • 不能使用空格,不能使用冒号
    • 不建议以XML、xml、Xml开头
    • 标签名不能数字开头,可以有数字
    • 可以使用下划线

    可以保持与Java命名标识符一样的规则

  6. 格式化良好的XML文档,有且仅有一个根元素。

属性

<person id="110">
  1. 属性是元素的一部分,它必须出现在元素的开始标签中

  2. 属性的定义格式:属性名=“属性值”,其中属性值必须使用单引或双引号括起来

  3. 一个元素可以有0~N个属性,但一个元素中不能出现同名属性
    在这里插入图片描述

  4. 属性名不能使用空格 , 建议不要使用冒号等特殊字符,且必须以字母开头

    建议以Java的标识符定义规则做参考

<person id="123">
	<name>张三</name>
</person>

注释

<!-- 注释内容 -->

<!-- 
注释内容 1
注释内容 2
-->

XML的注释与HTML相同,既以<!--开始,-->结束。不能嵌套。

Java中注释:

// 单行
/* */ 多行注释
/** */ 文档注释

XML注释:

<!-- 注释内容 -->
<!--<person>注释</person>-->  <!-- 快捷键:Ctrl+/ :可以将整行进行注释-->
<person>三生三世</person> <!-- 快捷键:Ctrl+Shift+/:局部注释-->

转义字符[实体字符]

XML中的实体字符与HTML一样。因为很多符号已经被文档结构所使用,所以在元素体或属性值中想使用这些符号就必须使用实体字符

在这里插入图片描述

字符预定义的转义字符说明
<&lt;小于(less than)
>&gt;大于(greater than)
"&quot;双引号(quotation)
&apos;单引号(apostrophe)
&&amp;和号(ampersand )

注意:严格地讲,在 XML 中仅有字符 “<“和”&” 是非法的。省略号、引号和大于号是合法的,但是把它们替换为实体引用是个好的习惯。

代码演示

​ 假如在 XML 文档中放置了一个类似 “<” 字符,那么这个文档会产生一个错误,这是因为解析器会把它解释为新元素的开始。因此你不能这样写:

<message>if salary < 1000 then </message>

为了避免此类错误,需要把字符 “<” 替换为实体引用,就像这样:

<message>if salary &lt; 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、 解析方式和解析器

开发中比较常见的解析方式有三种,如下:

  1. DOM:要求解析器把整个XML文档装载到内存,并解析成一个Document对象

a)优点:元素与元素之间保留结构关系,故可以进行增删改查操作。

b)缺点:XML文档过大,可能出现内存溢出

  1. SAX:是一种速度更快,更有效的方法。它逐行扫描文档,一边扫描一边解析。并以事件驱动的方式进行具体解析,每执行一行,都触发对应的事件。

a)优点:处理速度快,可以处理大文件

b)缺点:只能读,逐行后将释放资源,解析操作繁琐。

  1. 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/

库导入方式:

  1. 在IDEA中,选择项目鼠标右键—>弹出菜单–>open Module settings”–>Dependencies–>±->JARs or directories… 找到dom4j-1.6.1.jar,成功添加之后点击"OK" 即可。

  2. 直接右键选择: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值,以及书本名称,作者名称和价格.

步骤分析:

  1. 创建一个SaxReader对象,调用read方法加载一个xml文件获得文档对象
  2. 通过文档对象,获取根元素
  3. 通过根元素一层一层的进行解析子元素。
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语法方式:

  1. 绝对路径表达式方式 例如: /元素/子元素/子子元素…
  2. 相对路径表达式方式 例如: 子元素/子子元素… 或者 ./子元素/子子元素…
  3. 全文搜索路径表达式方式 例如: //子元素//子子元素
  4. 谓语(条件筛选)方式 例如:/元素/子元素[@id]
2、XPath解析XML案例
XPath绝对路径

格式:

String xpath="/根元素/子元素/子子元素...";

绝对路径是以"/"开头,一级一级的描述标签的层级路径就是绝对路径

(这里注意不可以跨层级)

需求:将素材中的Contact.xml拷贝到项目中,采用绝对路径获取从根节点开始逐层的查找name节点列表并打印信息

步骤:

  1. 先创建SAXReader对象,调用read方法,将Contact.xml关联,得到Document对象
  2. 定义绝对路径
  3. 调用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//namecontact无论在哪一种,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"));

        }
    }
}



  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 2
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 2
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

编程小栈

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值