XML入门笔记

2020-04-22  本文已影响0人  憨憨二师兄

XML的概念与用途

XML的概念

XML的用途

XML的文档结构

XML标签书写规则

合法的标签名

正确的标签格式示例:

<shop-cart>
  <item>相册</item>
</shop-cart>

适当的注释与缩进

适当的注释与缩进会增强阅读性

合理使用属性

特殊字符与CDATA标签的使用

有序的子元素

有序的子元素是指:在XML多层嵌套的子元素中,标签前后顺序应该保持一致

XML语义约束

XML语义约束就是用于规定XML文档中允许出现哪些元素
XML语义约束有两种定义方式:DTD 与 XML Schema

XML语义约束之DTD

DTD,即:Document Type Definition,翻译过来就是文档定义类型。DTD是一种简单易用的语句约束方式。
DTD文件的扩展名为.dtd

DTD语义约束示例

拿hr.xml文件进行举例,首先在同目录下创建hr.dtd文件,并在hr.xml文件中引入hr.dtd

<?xml version = "1.0" encoding = "UTF-8"?>
<!--人力资源管理-->
<!DOCTYPE hr SYSTEM "hr.dtd">
<hr>
    <employee no="27149">
        <name>张三</name>
        <age>31</age>
        <salary>4000</salary>
        <department>
            <dname>会计部</dname>
            <address>没有科技-103</address>
        </department>
    </employee>

    <employee no="27150">
        <name>李四</name>
        <age>29</age>
        <salary>10000</salary>
        <department>
            <dname>研发部</dname>
            <address>没有科技-104</address>
        </department>
    </employee>
</hr>

hr.dtd文件如下:

<?xml version = "1.0" encoding = "UTF-8"?>
<!ELEMENT hr (employee+)>
<!ELEMENT employee (name,age,salary,department)>
<!-- employee 中的 no 属性 属于 CDATA 即:不应该被XML解析的部分 默认值为 "" -->
<!ATTLIST employee no CDATA "">
<!-- #PCDATA 为 纯文本  -->
<!ELEMENT name (#PCDATA)>
<!ELEMENT age (#PCDATA)>
<!ELEMENT salary (#PCDATA)>
<!ELEMENT department (dname,address)>
<!ELEMENT dname (#PCDATA)>
<!ELEMENT address (#PCDATA)>

XML Schema

以hr.xml举例,对应的xsd文件为:

<?xml version="1.0" encoding="UTF-8" ?>
<xs:schema xmlns:xs="http://www.w3.org/2001/XMLSchema">
    <xs:element name="hr">
        <!--complexType标签的含义是复杂节点,包含子节点时必须使用这个标签-->
        <xs:complexType>
            <xs:sequence>
                <xs:element name="employee" minOccurs="1" maxOccurs="9999">
                    <xs:complexType>
                        <xs:sequence>
                            <xs:element name="name" type="xs:string"></xs:element>
                            <xs:element name="age">
                                <xs:simpleType>
                                    <xs:restriction base="xs:integer">
                                        <xs:minInclusive value="18"></xs:minInclusive>
                                        <xs:maxInclusive value="60"></xs:maxInclusive>
                                    </xs:restriction>
                                </xs:simpleType>
                            </xs:element>
                            <xs:element name="salary" type="xs:integer"></xs:element>
                            <xs:element name="department">
                                <xs:complexType>
                                    <xs:sequence>
                                        <xs:element name="dname" type="xs:string"></xs:element>
                                        <xs:element name="address" type="xs:string"></xs:element>
                                    </xs:sequence>
                                </xs:complexType>
                            </xs:element>
                        </xs:sequence>
                        <!--required 必须的;表明 no 这个属性在任何employee节点下必须存在-->
                        <xs:attribute name="no" type="xs:string" use="required"></xs:attribute>
                    </xs:complexType>
                </xs:element>
            </xs:sequence>
        </xs:complexType>
    </xs:element>
</xs:schema>

在hr.xml文件中引入这个xmd文件需要在根节点上加入:

<?xml version = "1.0" encoding = "UTF-8"?>
<!--人力资源管理-->
<!--<!DOCTYPE hr SYSTEM "hr.dtd">-->
<hr xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"  xsi:noNamespaceSchemaLocation="hr.xsd">
    <employee no="27149">
        <name>张三</name>
        <age>31</age>
        <salary>4000</salary>
        <department>
            <dname>会计部</dname>
            <address>没有科技-103</address>
        </department>
    </employee>

    <employee no="27150">
        <name>李四</name>
        <age>29</age>
        <salary>10000</salary>
        <department>
            <dname>研发部</dname>
            <address>没有科技-104</address>
        </department>
    </employee>
</hr>

XML文档解析及XPath语言

DOM文档模型与Dom4j

Dom4j读取遍历XML

继续使用hr.xml文件作为示例,首先需要引入dom4j的jar包,在这里就不赘述了,直接看代码即可:

package dom4j;

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

import java.util.List;

public class HrReader {

    public static void readXml(){
        String file = "C:/Users/11750/IdeaProjects/xml/src/hr.xml";
        // SAXReader类是读取XML文件的核心类,用于将XML解析后以树的形式保存在内存中
        SAXReader reader = new SAXReader();
        try {
            Document document = reader.read(file);
            // 获取XML文档的根节点
            Element root = document.getRootElement();
            List<Element> employees = root.elements("employee");
            for(Element employee : employees){
                // 获取属性
                Attribute no = employee.attribute("no");
                System.out.print(no.getText() + " ");

                // element方法用于获取唯一的子节点对象
                Element name = employee.element("name");
                String empName = name.getText(); // getText方法用于获取标签文本
                System.out.print(empName + " ");

                // or
                System.out.print(employee.elementText("age") + " ");
                System.out.print(employee.elementText("salary") + " ");

                //
                Element department = employee.element("department");
                System.out.print(department.elementText("dname") + " ");
                System.out.println(department.elementText("address") + " ");


                System.out.println();
            }
        } catch (DocumentException e) {
            e.printStackTrace();
        }
    }

    public static void main(String[] args) {
        HrReader.readXml();
    }
}

显示结果如下:


Dom4j 更新XML

Dom4j除了可以读取XML文档中数据,还可以向XML文档中写入数据,继续使用hr.xml文件作为示例,向hr.xml写入新的员工:

package dom4j;

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

import java.io.FileOutputStream;
import java.io.OutputStreamWriter;
import java.io.Writer;

public class HrWriter {

    public static void writeXml(){
        String file = "C:/Users/11750/IdeaProjects/xml/src/hr.xml";
        SAXReader reader = new SAXReader();
        try {
            Document document = reader.read(file);
            Element root = document.getRootElement();
            Element newEmp = root.addElement("employee");

            // add attribute
            newEmp.addAttribute("no","3311");

            // set name
            Element name = newEmp.addElement("name");
            name.setText("王五");

            // set age
            newEmp.addElement("age").setText("26");

            // set salary
            newEmp.addElement("salary").setText("5200");

            // set
            Element department = newEmp.addElement("department");
            department.addElement("dname").setText("人事部");
            department.addElement("address").setText("没有科技-105");

            // 输出流写入到 xml 文件中
            Writer writer = new OutputStreamWriter(new FileOutputStream(file),"UTF-8");
            document.write(writer);
            writer.close();
        } catch (Exception e) {
            e.printStackTrace();
        }
    }

    public static void main(String[] args) {
        HrWriter.writeXml();
    }

}

更新XML文档后,发现已经添加了王五这名原工的信息,再次使用HrReader.readXml() 遍历所有员工可以得到:

XPath路径表达式

几种最常用的基本表达式有:

表达式 描述
nodename 选取此节点的所有子节点
/ 从根节点选取
// 从匹配选择的当前节点选择文档中的节点,而不考虑它们的位置
. 选取当前节点
.. 选取当前节点的父节点
@ 选取属性

XPath基本表达式案例

路径表达式 结果
bookstore 选取bookstore元素的所有子节点
/bookstore 选取根元素bookstore
bookstore/book 选取属于 bookstore 的子元素的所有book元素
//book 选取所有book子元素,而不管它们在文档中的位置
bookstore//book 选取bookstore元素的后代的所有book元素,而不管他们位于bookstore下面的什么位置
//@lang 选取名为lang的所有属性

XPath 谓语表达式

路径表达式 结果
/bookstore/book[1] 选取bookstore子元素的第一个book元素
/bookstore/book[last()] 选取属于bookstore子元素的最后一个 book元素
/bookstore/book[last() - 1] 选取属于bookstore子元素的倒数第二个 book元素
/bookstore/book[position() < 3] 选取最前面的两个属于bookstore元素的子元素的book元素
//title[@lang] 选取所有拥有名为lang的属性的title元素
//title[@lang='eng'] 选取所有title元素,且这些元素拥有值为eng的lang属性
/bookstore/book[price > 35.00] 选取bookstore 元素的所有book元素,且其中price的值要大于35.00
/bookstore/book[price > 35.00]/title 选取bookstore 元素的所有book元素下的title元素,且其中price的值要大于35.00

Jaxen与XPath实战

Jaxen

Dom4j里面提供了用来支持XPath的方法,不过使用XPath表达式之前,还需要引入支持XPath的jar包。

示例如下:

hr.xml文件:

<?xml version="1.0" encoding="UTF-8"?>
<!--人力资源管理--><!--<!DOCTYPE hr SYSTEM "hr.dtd">-->
<hr xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:noNamespaceSchemaLocation="hr.xsd">
    <employee no="3301">
        <name>李铁柱</name>
        <age>37</age>
        <salary>3600</salary>
        <department>
            <dname>人事部</dname>
            <address>XX大厦-B105</address>
        </department>
    </employee>
    <employee no="3302">
        <name>林海</name>
        <age>50</age>
        <salary>7000</salary>
        <department>
            <dname>财务部</dname>
            <address>XX大厦-B106</address>
        </department>
    </employee>
    <employee no="3303">
        <name>安娜</name>
        <age>24</age>
        <salary>4600</salary>
        <department>
            <dname>人事部</dname>
            <address>XX大厦-B105</address>
        </department>
    </employee>
    <employee no="3304">
        <name>张晓宇</name>
        <age>29</age>
        <salary>3000</salary>
        <department>
            <dname>后勤部</dname>
            <address>XX大厦-B108</address>
        </department>
    </employee>

    <employee no="3305">
        <name>赵子轩</name>
        <age>19</age>
        <salary>1500</salary>
        <department>
            <dname>后勤部</dname>
            <address>XX大厦-B108</address>
        </department>
    </employee>

    <employee no="3306">
        <name>张晓璇</name>
        <age>20</age>
        <salary>1700</salary>
        <department>
            <dname>后勤部</dname>
            <address>XX大厦-B108</address>
        </department>
    </employee>
    <employee no="3307">
        <name>张檬</name>
        <age>43</age>
        <salary>8700</salary>
        <department>
            <dname>会计部</dname>
            <address>XX大厦-B103</address>
        </department>
    </employee>
    <employee no="3308">
        <name>李梅</name>
        <age>33</age>
        <salary>8700</salary>
        <department>
            <dname>工程部</dname>
            <address>XX大厦-B104</address>
        </department>
    </employee>
    <employee no="3309">
        <name>张三</name>
        <age>31</age>
        <salary>4000</salary>
        <department>
            <dname>会计部</dname>
            <address>XX大厦-B103</address>
        </department>
    </employee>
    <employee no="3310">
        <name>李四</name>
        <age>23</age>
        <salary>3000</salary>
        <department>
            <dname>工程部</dname>
            <address>XX大厦-B104</address>
        </department>
    </employee>
</hr>

引入Jaxen的jar包:jaxen-1.1.6.jar后,对XPath的测试程序如下:

package dom4j;

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

import java.util.List;

public class XPathTest {
    public static void xPath(String xPathExp){
        String file = "C:/Users/11750/IdeaProjects/xml/src/hr.xml";
        SAXReader reader = new SAXReader();
        try {
            Document document = reader.read(file);
            // 执行 XPath表达式:document.selectNodes(xPathExp)
            // Node 为 Element和 Attribute 的父类
            List<Node> nodes = document.selectNodes(xPathExp);
            for(Node node : nodes){
                Element emp = (Element) node;
                System.out.println("编号: " + emp.attributeValue("no"));
                System.out.println("姓名: " + emp.elementText("name"));
                System.out.println("年龄: " + emp.elementText("age"));
                System.out.println("薪水: " + emp.elementText("salary"));
                System.out.println("===============");
            }
        } catch (Exception e) {
            e.printStackTrace();
        }
    }

    public static void main(String[] args) {
        // 获取到所有的employee节点
        XPathTest.xPath("/hr/employee");
        XPathTest.xPath("//employee");
        // 统计所有工资小于4000的员工
        XPathTest.xPath("//employee[salary<4000]");
        // 查询李铁柱这名员工的信息
        XPathTest.xPath("//employee[name='李铁柱']");
        // 查询编号为3304的这名员工的信息
        XPathTest.xPath("//employee[@no=3304]");
        // 查询第一个员工的信息
        XPathTest.xPath("//employee[1]");
        // 查询最后一个员工的信息
        XPathTest.xPath("//employee[last()]");
        // 查询前五个员工的信息
        XPathTest.xPath("//employee[position()<6]");
        // 查询第三名员工和第八名员工的信息
        XPathTest.xPath("//employee[3] | //employee[8]");
    }
}

上一篇 下一篇

猜你喜欢

热点阅读