JavaSE# 笔记【XML XML约束 DOM4J XPath 方法引用】@Gray

1.XML

1.1XML介绍

​ XML 指可扩展标记语言(Extensible Markup Language)

​ XML中没有预定义标签,所有的标签都是自己定义的。

​ XML是W3C组织的一个语言。

​ W3C在1988年2月发布XML1.0版本,我们现在用的就是1.0版本。在后面也有新的版本,但是新版本不太兼容旧版本,所以新版本没有被推广开。

1.2编写XML

<天气预报>
    <北京>
        <东城区>
            <最高温度>12℃</最高温度>
            <最低温度>-2℃</最低温度>
        </东城区>
        <西城区>
            <最高温度>13℃</最高温度>
            <最低温度>-1℃</最低温度>
        </西城区>
        <顺义区>
            <最高温度>14℃</最高温度>
            <最低温度>-3℃</最低温度>
        </顺义区>
    </北京>
    <天津>
        <武清区>
            <最高温度>15℃</最高温度>
            <最低温度>2℃</最低温度>
        </武清区>
        <南开区>
            <最高温度>20℃</最高温度>
            <最低温度>6℃</最低温度>
        </南开区>
    </天津>
</天气预报>

1.3XML的作用

  1. 可以传输数据,作为数据传输的载体

  2. 可以作为配置文件,保存配置信息

    properties用来存储一对一的键值对信息,xml用来存储有上下级关系的信息

1.4XML的组成部分

文档声明

<?xml version="1.0" encoding="UTF-8" ?>
  • 注意事项:

    1.文档声明必须以<?xml开头 , 必须以?>结尾
    2.文档声明必须写在第一行第一列
    3.version表示版本,encoding表示编码
    4.文档声明可以不写
    

元素

  1. 元素是XML中最重要的组成部分,元素也叫标签

  2. 标签分为开始标签和结束标签,开始标签<名字> 结束标签</名字>

  3. 开始标签和结束标签中间写的是标签内容,标签的内容可以是文本,也可以是其他标签

  4. 如果标签没有任何内容,那么可以定义为 自闭合标签(<名字/>)

  5. 命名规则:
    ​ 不要使用XML xML xml 写样的单词

    ​ 不能使用空格,冒号等特殊字符

    ​ 命名区分大小写

  6. 一个XML文件有且仅有一个根标签

属性

  1. 属性是标签的一部分,属性必须写在开始标签或自闭合标签中,不能写在结束标签中

  2. 属性的书写格式:属性名=属性值,属性值必须使用单引号或双引号括起来,在XML中,单引和双引是没区别的。

  3. 一个元素可以有任意个属性,但是属性之间不能重名,多个属性之间用空格隔开

  4. 属性名不能使用特殊字符,必须以字母开头

注释

  • 对代码的解释说明

    <!-- 注释  -->
    快捷键: ctrl+/   (是idea的注释快捷键,idea会自动识别语言匹配对应的注释)
    

转义字符

​ 有些特殊的字符在XML中是会被识别的,比如<在XML中会被识别为标签,如果想要写这样的符号,需要用转义字符.

<      &lt;
>      &gt;
"      &quot;
<abc> 3 &lt; 4   </abc>

CDATA区 (了解)

​ 如果有大量的转义字符,可能就降低代码的阅读性,所以可以使用CDATA区去代替转义字符,在CDATA区中的文本不会被识别为特殊符号。

<!--CDATA区-->
<abc>   <![CDATA[  <<<<<<<>>>>>>>>   ]]>      </abc>

2.约束

2.1概念

​ 因为XML语言没有任何预定义标签,写任何标签都是可以的,这样导致解析比较困难复杂。

​ 约束是对XML文件进行限制的,约束可以规定XML的标签内容和嵌套方式。

​ 约束文件一定不会让我们自己写,但是今天理解一下约束的内容。

2.2DTD约束

  • 介绍

    • DTD约束写法简单,但是对XML的约束不是很严格,无法约束具体的数据类型。
    • DTD约束的文件后缀名.dtd
  • DTD约束文档

    <!--
        复制内容如下到XML文件中:
            <!DOCTYPE 书架 SYSTEM "bookdtd.dtd">
    
    -->
            <!--Element表示元素,元素名称是书架,书架里书作为子元素-->
            <!ELEMENT 书架 (+)>
            <!--书也是一个元素,书的子元素是书名,作者,售价-->
            <!ELEMENT 书 (书名,作者,售价)>
            <!--书名也是一个元素,#PCDATA表示书名里面是文本-->
            <!ELEMENT 书名 (#PCDATA)>
            <!--作者也是一个元素,#PCDATA表示作者里面是文本-->
            <!ELEMENT 作者 (#PCDATA)>
            <!--售价也是一个元素,#PCDATA表示售价里面是文本-->
            <!ELEMENT 售价 (#PCDATA)>
    
  • DTD引入方式

    • xml需要使用DTD就要先引入dtd,但是这个代码一定不用我们写,一定是会提供的。
    1.内部DTD,在XML文档内部嵌入DTD,只对当前XML有效
     	<!DOCTYPE 根元素 [...//具体语法]>
     	
    2.外部DTD—本地DTD
    	<!DOCTYPE 根元素 SYSTEM "约束文件名称">
    	
    3.外部DTD—公共DTD
    	<!DOCTYPE 根标签 PUBLIC "dtd的名字" "网络上的位置">
    
  • 按照上面的dtd约束编写XML

    <!DOCTYPE 书架 SYSTEM "bookdtd.dtd">
    <书架>
        <>
            <书名>java从入门到放弃</书名>
            <作者>高斯林</作者>
            <售价>99.8</售价>
        </>
    </书架>
    
  • DTD约束的符号介绍

    ?	:表示一个或零个
    *   :表示任意个
    +   :表示一个或多个
    
    ,	:表示按照顺序依次出现
    |   :表示或者
    

2.3Schema约束

  • 介绍

    • Schema约束能够对xml做出更严格的限制,可以对数据类型做精确的要求。
    • Schema约束的后缀名是.xsd
  • Schema约束文档

    <?xml version="1.0" encoding="UTF-8" ?>
    <!--    传智播客教学实例文档.将注释中的以下内容复制到要编写的xml的声明下面
    
    
    复制内容如下到XML文件中:
    
    <书架 xmlns="http://www.itcast.cn"
    xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
    xsi:schemaLocation="http://www.itcast.cn bookSchema.xsd" >
    
    </书架>
    
    
    -->
    <xs:schema
            xmlns:xs="http://www.w3.org/2001/XMLSchema"
            targetNamespace="http://www.itcast.cn"
            elementFormDefault="qualified">
        <!--element表示元素 元素名是书架-->
        <xs:element name='书架'>
            <!--complextype表示书架是一个复杂标签(里面有子标签)-->
            <xs:complexType>
                <!--sequence表示顺序出现   maxOccurs表示最大出现次数-->
                <xs:sequence maxOccurs="3" >
                    <!--书架的子标签是书-->
                    <xs:element name=''>
                        <!--表示书也是一个复杂标签(里面有子标签)-->
                        <xs:complexType>
                            <!--书里面的子标签要顺序出现-->
                            <xs:sequence>
                                <!--书名是书的子标签  type表示类型-->
                                <xs:element name='书名' type='xs:string'/>
                                <!--作者是书的子标签  type表示类型-->
                                <xs:element name='作者' type='xs:string'/>
                                <!--售价是书的子标签  type表示类型-->
                                <xs:element name='售价' type='xs:double'/>
                            </xs:sequence>
                        </xs:complexType>
                    </xs:element>
                </xs:sequence>
            </xs:complexType>
        </xs:element>
    </xs:schema>
    
  • 根据上面的Schema约束编写XML

    <书架 xmlns="http://www.itcast.cn"
        xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
        xsi:schemaLocation="http://www.itcast.cn bookSchema.xsd" >
    
        <>
            <书名>java入门当放弃</书名>
            <作者>詹姆斯高斯林</作者>
            <售价>99.8</售价>
        </>
    
        <>
            <书名>java入门当放弃</书名>
            <作者>詹姆斯高斯林</作者>
            <售价>99.8</售价>
        </>
    
    
        <>
            <书名>java入门当放弃</书名>
            <作者>詹姆斯高斯林</作者>
            <售价>99.8</售价>
        </>
    
    </书架>
    
  • 结论

    不管是DTD还是Schema约束,约束文件是不会让你写的。

    使用任何约束,都需要在XML中引入约束,引入的方式直接复制就可以了。

3.DOM4J

1.解析方式

​ DOM:DOM方式的意思是把整个XML文件读取到内存中,然后解析其中的内容。

​ 缺点:如果文件太大,可能导致内存不够用。

​ 优点:可以对整个文档进行增删改查操作。

​ SAX: 读取一部分到内存中,解析完一部分之后释放内存再读取下一部分。

​ 缺点:无法对整个文档进行增删改查操作。

​ 优点:不占用大量内存,不会出现内存溢出。

2.解析开发包

​ JAXP: 这个工具是JDK中自带的解析开发包,用的时候不需要另外下载。

​ DOM4J: 这个开发包是第三方提供的,简单好用,如果使用需要下载jar包。

​ JSOUP: 这个开发包是用来解析HTML文件的,也可以用来解析XML,需要下载jar包。

3.DOM4J解析

3.1 方法介绍

创建解析器对象:
	SAXReader sr = new SAXReader();
解析器读取文件方法:
	Document doc = sr.read(String fileName);
Document的方法:
	getRootElement()			: 获取根元素	
	
节点中的方法:	
	elements()     				: 获取当前元素的子元素
	element(String name)		: 根据元素名获取指定子元素(如果有多个就获取到第一个)
	getName()					: 获取元素的元素名
	attributeValue(String name)	: 获取当前元素下某个属性的值
	elementText(String name)	: 获取指定子元素的文本值,参数是子元素名称
	getText()					: 获取当前元素的文本值

3.2 代码演示

  • XML文件

    <天气预报>
        <北京>
            <东城区>
                <最高温度>12℃</最高温度>
                <最低温度>-2℃</最低温度>
            </东城区>
            <西城区>
                <最高温度>13℃</最高温度>
                <最低温度>-1℃</最低温度>
            </西城区>
            <顺义区>
                <最高温度>14℃</最高温度>
                <最低温度>-3℃</最低温度>
            </顺义区>
        </北京>
    
    
        <天津 jc="" level="1.5线">
            <武清区>
                <最高温度>15℃</最高温度>
                <最低温度>2℃</最低温度>
            </武清区>
            <南开区>
                <最高温度>20℃</最高温度>
                <最低温度>6℃</最低温度>
            </南开区>
        </天津>
    </天气预报>
    
  • java代码

import org.dom4j.Document;
import org.dom4j.DocumentException;
import org.dom4j.Element;
import org.dom4j.io.SAXReader;

import java.util.List;

public class Test01 {
    public static void main(String[] args) throws DocumentException {
        //1.获取解析器对象
        SAXReader reader = new SAXReader();
        //2.读取文件
        //Document叫文档
        Document document = reader.read("day15\\tqyb.xml");

        //获取根元素
        Element rootE = document.getRootElement();

        //elements()             : 获取当前元素的子元素
        List<Element> list = rootE.elements();
        //遍历集合
        for (Element element : list) {
            System.out.println(element.getName());
        }

        System.out.println("=========================");

        //element(String name)    : 根据元素名获取指定子元素(如果有多个就获取到第一个)
        Element e = rootE.element("天津");
        System.out.println(e);
        System.out.println("==========================");

        //getName()                : 获取元素的元素名
        System.out.println(e.getName());  //天津

        System.out.println("==========================");
        //attributeValue(String name)  : 获取当前元素下某个属性的值
        String value = e.attributeValue("jc");
        System.out.println(value);   //津
        String value2 = e.attributeValue("level");
        System.out.println(value2);  //1.5线

        System.out.println("==========================");
        //elementText(String name) : 获取指定子元素的文本值,参数是子元素名称
        //通过‘天津’获取‘武清区’这个子元素
        Element e2 = e.element("武清区");
        //获取武清区最高温度的值
        String s = e2.elementText("最高温度");
        System.out.println(s);   //15℃

        System.out.println("==========================");
        //getText()                : 获取当前元素的文本值
        Element e3 = e2.element("最高温度");
        String s3 = e3.getText();
        System.out.println(s3);    //15℃
    }
}

4.XPath演示

4.1 介绍

  • XPath是路径的表现形式,可以快速的定位XML中的元素。

  • Node中的两个方法可以使用XPath:

    • Node是XML中各种类型的父类,比如Node是Element的父类
List selectNodes("表达式")				:使用Xpath作为参数查找多个元素
Node selectSingleNode("表达式")        :使用Xpath作为参数查找某个元素(默认获取第一个)

4.2 Xpath表达式写法

  • 绝对路径表达式方式

    • 以/开始的路径叫绝对路径,绝对路径是根节点开始查询。
  • 相对路径表达式方式

    • 不以/开始的路径叫相对路径,相对路径是相对于当前节点。
  • 全文搜索路径表达式方式

    • 在路径中使用//表示全文搜索,也就是可以忽略中间的层级
  • 谓语条件查询 (了解)

    • 元素[@属性名=’属性值‘]
    
    import org.dom4j.Document;
    import org.dom4j.DocumentException;
    import org.dom4j.Node;
    import org.dom4j.io.SAXReader;
    
    import java.util.List;
    
    public class Test02 {
        public static void main(String[] args) throws DocumentException {
            //1.获取解析器对象
            SAXReader reader = new SAXReader();
    
            //2.读取文件
            Document document = reader.read("day15\\tqyb.xml");
    
            //Node表示结点,在XML中所有的类型都属于Node
            //Element是Node的子类
            //Attribute是Node的子类
    
            //List selectNodes("xpath表达式")          :使用Xpath作为参数查找多个元素
            //Node selectSingleNode("xpath表达式")        :使用Xpath作为参数查找某个元素(默认获取第一个)
            //绝对路径:
            List<Node> list = document.selectNodes("/天气预报/北京/东城区");
            //遍历集合
            for (Node node : list) {
                System.out.println(node.getName());
            }
            System.out.println("--------------------");
            Node node = document.selectSingleNode("/天气预报/北京/东城区");
            System.out.println(node.getName());
    
            System.out.println("====================");
            //相对路径
            //通过东城区获取西城区
            Node node1 = node.selectSingleNode("../西城区");
            System.out.println(node1.getName());
            //通过西城区获取武清区
            Node node2 = node1.selectSingleNode("../../天津/武清区");
            System.out.println(node2.getName());
    
            System.out.println("===================");
            //全文搜索
            //获取所有的最高温度
            List<Node> list2 = document.selectNodes("//最高温度");
            for (Node node3 : list2) {
                System.out.println(node3.getText());
            }
            System.out.println("-----------------");
            //获取北京里面所有的最高温度
            List<Node> list3 = document.selectNodes("//北京//最高温度");
            for (Node node3 : list3) {
                System.out.println(node3.getText());
            }
            System.out.println("-----------------");
            //获取东城区的最高温度
            Node node3 = document.selectSingleNode("//东城区//最高温度");
            System.out.println(node3.getText());  //13℃
    
            //谓语查询(条件查询)
            System.out.println("=====================");
            Node node4 = document.selectSingleNode("//最高温度[@level='a']");
            System.out.println(node4.getText());   //15℃
    
    
        }
    }
    

5.方法引用

  • 作用

    方法引用是为了简化代码,在JDK1.8之后出现的技术。用来代替某些Lambda表达式。

    当Lambda表达式中大括号只有一行代码,且这句代码是在调用别的方法并且没有额外参数的时候,就可以简化成方法引用。

  • 代码

    1.
       //Lambda表达式大括号中只有一个输出语句,输出语句就是调用println()方法,所以可以简化成方法引用
       stream.forEach(s->System.out.println(s));
       //            对象名::方法名
       stream.forEach(System.out::println);
       
    2.
     //Lambda表达式大括号中只有一个s.length()方法,就可以使用方法引用,变成调用String类的length()方法   
     stream.map((String s)->{return s.length();}).forEach(System.out::println);
     //         类名::方法名
     stream.map(String::length).forEach(System.out::println);
    
    
    3.  
     //Lambda表达式大括号中只调用了Person的构造方法,且没有传入其他的参数,唯一的参数就是Lambda表达式内的参数name,可以使用方法引用
    stream4.map(name->new Person(name)).forEach(System.out::println);
     //          类名::new   (表示调用类的构造方法)
    stream4.map(Person::new).forEach(System.out::println);
    
    
    4.
    //函数式接口--------------
    @FunctionalInterface
    public interface Inter {
    
        //抽象方法
        String method(int[] arr);
    }
    
    //测试类--------------------
    public class Test01 {
        public static void main(String[] args) {
    
            //要求:如何在main方法中调用show方法
    
            //匿名内部类
            show(new Inter() {
                @Override
                public String method(int[] arr) {
                    //因为Arrays.toString()方法能够把数组转成字符串,所以我们就调用这个方法
                    return Arrays.toString(arr);
                }
            });
    
            //Lambda表达式(因为Inter是函数式接口)
            show((int[] arr)->{return Arrays.toString(arr);});
    
            //lambda表达式可以简化
            show(arr->Arrays.toString(arr));
    
            //lambda表达式大括号只有一行代码,且代码是在调用别的方法 方法也没有其他参数。
            //方法引用(直接调用Arrays类的toString方法)
            show(Arrays::toString);
        }
    
    
        //方法
        public static void show(Inter i){
            //定义数组
            int[] arr = {11,22,33};
            //调用接口的方法
            String s = i.method(arr);
            //输出结果
            System.out.println(s);
        }
    }
    
    ``
    
    

结论

匿名内部类
	要使用父类的子类对象或使用接口的子类对象时
	
Lambda
	如果匿名内部类的接口是函数式接口,就可以使用Lambda
	
方法引用
	如果Lambda的大括号中只有一行代码,且是在调用别的方法,并且没有传其他参数(最多只能有lambda表达式方法自己的参数) 就可以使用方法引用
	
只要在idea上有灰色或黄色提示,就可以按alt + enter 简化
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值