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的作用
-
可以传输数据,作为数据传输的载体
-
可以作为配置文件,保存配置信息
properties用来存储一对一的键值对信息,xml用来存储有上下级关系的信息
1.4XML的组成部分
文档声明
<?xml version="1.0" encoding="UTF-8" ?>
-
注意事项:
1.文档声明必须以<?xml开头 , 必须以?>结尾 2.文档声明必须写在第一行第一列 3.version表示版本,encoding表示编码 4.文档声明可以不写
元素
-
元素是XML中最重要的组成部分,元素也叫标签
-
标签分为开始标签和结束标签,开始标签<名字> 结束标签</名字>
-
开始标签和结束标签中间写的是标签内容,标签的内容可以是文本,也可以是其他标签
-
如果标签没有任何内容,那么可以定义为 自闭合标签(<名字/>)
-
命名规则:
不要使用XML xML xml 写样的单词 不能使用空格,冒号等特殊字符
命名区分大小写
-
一个XML文件有且仅有一个根标签
属性
-
属性是标签的一部分,属性必须写在开始标签或自闭合标签中,不能写在结束标签中
-
属性的书写格式:属性名=属性值,属性值必须使用单引号或双引号括起来,在XML中,单引和双引是没区别的。
-
一个元素可以有任意个属性,但是属性之间不能重名,多个属性之间用空格隔开
-
属性名不能使用特殊字符,必须以字母开头
注释
-
对代码的解释说明
<!-- 注释 --> 快捷键: ctrl+/ (是idea的注释快捷键,idea会自动识别语言匹配对应的注释)
转义字符
有些特殊的字符在XML中是会被识别的,比如<在XML中会被识别为标签,如果想要写这样的符号,需要用转义字符.
< <
> >
" "
<abc> 3 < 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 简化