01-XML

nobility 发布于 2021-08-31 2378 次阅读


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='王五'] ");  //竖线代表并集
此作者没有提供个人介绍
最后更新于 2021-08-31