XML
XML简介
XML(EXtensible Markup Language)可扩展标记语言,与HTML类似,但是无任何预定义标签,扩展名为.xml,通常用于保存和传输数据,当今XML格式用途如下:
- Java程序配置描述文件
- 保存程序生产的数据
- 网络间数据传输
XML语法
- XML文档声明必须在第一行
- XML文档必须有根元素,且大小写敏感
- XML元素都必须有一个关闭标签,注释与HTML一致
- 特殊字符与HTML一致也需要使用实体转义,也可以使用
<![CDATA[ 内容 ]]>
标记,该标签中的内容不会被XML解析,而是当作普通字符串 - XML键值对属性值必须加引号,通常表示ID等必要属性时才会使用键值对方式
<?xml version="1.0" encoding="UTF-8"?>
<!-- version是XML解析版本,encoding设置字符集 -->
<class>
<student no="1">
<name>张三</name>
<sex>男</sex>
</student>
<student no="2">
<name>李四</name>
<sex>女</sex>
</student>
</class>
XML语义约束
XML语义约束就是规范XML文档标签规范
DTD文件约束
DTD(Document Type Definition)文档类型定义,扩展名为**.dtd**,本质上其实也是XML文件,XML关联该文件可简单进行语义约束
XML中使用<!DOCTYPE 根节点 SYSTEM "xxx.dtd">
导入dtd文件,DTD中使用<!ELEMENT>
标签对XML文件中标签进行约束,具体语法如下:注意空格
<!ELEMENT class (student)> <!-- class节点中只允许出现一个student节点 -->
<!ELEMENT class (student+)> <!-- 最少有一个student节点 -->
<!ELEMENT class (student?)> <!-- 最多有一个student节点 -->
<!ELEMENT class (student*)> <!-- 任意多个student节点 -->
<!ELEMENT student (name,sex)> <!-- class节点中只允许出现一个name和sex节点,并且顺序不能反 -->
<!ELEMENT name (#PCDATA)> <!-- name节点中只能是文本节点 -->
<!ATTLIST class no CDATA ""> <!-- class节点中可有一个字符串类型的no键值对属性,默认值是空字符串 -->
XML Schema约束
相比DTD格式更加复杂,功能也更加强大,是W3C标准,扩展名为**.xsd**,本质上其实也是XML文件,XML关联该文件可简单进行语义约束
在Eclipse中以下XML Schema没有问题,但是在IDEA中却无法检测,原因是在IDEA中语法更加严格
<?xml version="1.0" encoding="UTF-8"?>
<schema xmlns="http://www.w3.org/2001/XMLSchema"> <!--所有约束在schema标签中属性-->
<element name="class"> <!--element代表节点,使用name属性确定XML中的节点-->
<complexType> <!--complexType标签代表复杂节点,即包含子节点的节点-->
<sequence> <!--sequence标签代表内部节点顺序不可更改-->
<element name="student" minOccurs="0" maxOccurs="9999"> <!--使用minOccurs和maxOccurs属性限制节点数量-->
<complexType>
<sequence>
<element name="name" type="string"></element> <!--使用type属性确定XML中文本节点类型-->
<element name="sex">
<simpleType> <!--对文本节点类型做简单的限制-->
<restriction base="integer"> <!--base属性确定数据类型-->
<minInclusive value="0"></minInclusive> <!--最小值为0-->
<maxInclusive value="1"></maxInclusive> <!--最小值为1-->
</restriction>
</simpleType>
</element>
</sequence>
<attribute name="no" type="integer" use="required"></attribute> <!--attribute代表属性节点,use=required代表该属性是必须的-->
</complexType>
</element>
</sequence>
</complexType>
</element>
</schema>
<!--test.xml文件-->
<?xml version="1.0" encoding="UTF-8"?>
<class xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:noNamespaceSchemaLocation="test.xsd">
<student no="1">
<name>张三</name>
<sex>1</sex>
</student>
<student no="2">
<name>李四</name>
<sex>0</sex>
</student>
</class>
解决方案:为schema添加命名空间,改为如下代码
<?xml version="1.0" encoding="UTF-8"?>
<xs:schema xmlns:xs="http://www.w3.org/2001/XMLSchema"> <!--所有约束在schema标签中属性-->
<xs:element name="class"> <!--element代表节点,使用name属性确定XML中的节点-->
<xs:complexType> <!--complexType标签代表复杂节点,即包含子节点的节点-->
<xs:sequence> <!--sequence标签代表内部节点顺序不可更改-->
<xs:element name="student" minOccurs="0" maxOccurs="9999"> <!--使用minOccurs和maxOccurs属性限制节点数量-->
<xs:complexType>
<xs:sequence>
<xs:element name="name" type="xs:string"></xs:element> <!--使用type属性确定XML中文本节点类型-->
<xs:element name="sex">
<xs:simpleType> <!--对文本节点类型做简单的限制-->
<xs:restriction base="xs:integer"> <!--base属性确定数据类型-->
<xs:minInclusive value="0"></xs:minInclusive> <!--最小值为0-->
<xs:maxInclusive value="1"></xs:maxInclusive> <!--最小值为1-->
</xs:restriction>
</xs:simpleType>
</xs:element>
</xs:sequence>
<xs:attribute name="no" type="xs:integer" use="required"></xs:attribute> <!--attribute代表属性节点,use=required代表该属性是必须的-->
</xs:complexType>
</xs:element>
</xs:sequence>
</xs:complexType>
</xs:element>
</xs:schema>
Java解析XML
Java解析XML需要借助Dom4j,需要引入相关jar包,从maven官网中查找Dom4j并下载,导入项目即可,但是maven中的Dom4j版本有点老,也可以访问Dom4j官网下载较新版本
基本使用
查询
String file = "test.xml"; //XML文件路径
SAXReader reader = new SAXReader(); //创建读取解析XML的对象
try {
Document document = reader.read(file); //使用XML解析对象的read方法将XML文件读取到内存中
Element rootElement = document.getRootElement(); //获取XML中的根节点
List<Element> students = rootElement.elements("student"); //读取根元素下的所有名为student的元素
for (Element e : students){ //遍历返回的节点集合
Element nameElement = e.element("name"); //获取student的子节点
String name = nameElement.getText(); //获取子节点中的文本
System.out.println(name);
String sex = e.elementText("sex"); //获取sex的子节点中的文本
System.out.println(sex);
Attribute noAttribute = e.attribute("no"); //获取no属性
String no = noAttribute.getText(); //获取属性的文本
System.out.println(no);
}
} catch (Exception e) {
e.printStackTrace();
}
更新
要注意的是更新操作并不会对XML做语义约束
String file = "test.xml"; //XML文件路径
SAXReader reader = new SAXReader(); //创建读取解析XML的对象
try {
Document document = reader.read(file); //使用XML解析对象的read方法将XML文件读取到内存中
Element rootElement = document.getRootElement(); //获取XML中的根节点
Element student = rootElement.addElement("student"); //向根节点添加一个student节点
student.addAttribute("no","3"); //为创建的student节点添加no属性值为3
Element name = student.addElement("name"); //为创建的student节点添加name节点
name.addText("王五"); //为创建的name节点添加文本内容
Element sex = student.addElement("sex"); //为场景的student节点添加sex属性
sex.addText("女"); //为创建的sex节点添加文本内容
Writer writer = new OutputStreamWriter(new FileOutputStream(file),"UTF-8"); //创建文件输出流并转化为Writer对象
document.write(writer); //将修改后的内容写回XML文件中
writer.close(); //释放文件输出流资源
} catch (Exception e) {
e.printStackTrace();
}
XPath路径表达式
XPath路径表达式是XML文件中查找数据的语言,Java解析XPath需要借助jaxen,需要引入相关jar包,需要引入相关jar包,从maven官网中查找jaxen并下载,导入项目即可
public static void XPath(String query) { //传递XPath表达式
String file = "test.xml"; //XML文件路径
SAXReader reader = new SAXReader(); //创建读取解析XML的对象
try {
Document document = reader.read(file); //使用XML解析对象的read方法将XML文件读取到内存中
List<Node> nodes = document.selectNodes(query); //执行Xpath表达式,返回Node集合,因为可能是属性节点
for (Node node : nodes) {
Element element = (Element) node; //强转为Element,并输出内容
System.out.print(element.attributeValue("no") + ",");
System.out.print(element.elementText("name") + ",");
System.out.println(element.elementText("sex"));
}
} catch (Exception e) {
e.printStackTrace();
}
}
基本表达式
表达式 | 描述 |
---|---|
/ |
从根节点选取,/nodename 选取根元素nodename ,/nodename/child 选取从根节点下的所有child 子节点 |
// |
从匹配节点选取,//nodename 选取所有nodename 节点 |
nodename |
选取nodename 节点的所有子节点 |
. |
选取当前节点 |
.. |
选取当前节点的父节点 |
@ |
选取属性 |
XPath("//student"); //任意节点下的student节点
System.out.println("----------");
XPath("/class//student"); //class节点下的所有student节点
System.out.println("----------");
XPath("/class/student"); //class节点下的student节点
System.out.println("----------");
XPath("/class/student/."); //class节点下的student节点,点为当前节点
System.out.println("----------");
XPath("/class/student/name/.."); //class节点下的student节点,点点为父节点节点
谓语表达式
表达式 | 描述 |
---|---|
[1] |
第一个节点 |
[last()] |
最后一个节点 |
[last()-1] |
倒数第一个节点 |
[position()<3] |
前两个节点 |
[@attr] |
有attr属性的节点 |
[@attr="a"] |
有attr属性的节点且值为a |
[el>1] |
el 值大于1的节点 |
XPath("/class/student[1]"); //class节点下的第一个student节点
System.out.println("----------");
XPath("/class/student[2]"); //class节点下的第一个student节点
System.out.println("----------");
XPath("/class/student[last()]"); //class节点下的最后一个student节点
System.out.println("----------");
XPath("/class/student[last()-1]"); //class节点下的倒数第二个student节点
System.out.println("----------");
XPath("/class/student[position()<3]"); //class节点下的前两个student节点
System.out.println("----------");
XPath("/class/student[@no='2']"); //class节点下no属性为2的student节点
System.out.println("----------");
XPath("/class/student[name='李四']"); //class节点下子节点name值为李四的student节点
System.out.println("----------");
XPath("/class/student[sex<'1']"); //class节点下子节点sex值小于1的student节点
System.out.println("----------");
XPath("/class/student[name='李四']|/class/student[name='王五'] "); //竖线代表并集
Comments NOTHING