XML学习 --- 可扩展标记语言

XML的应用

  • 使用实例:qq消息发送,利于程序的维护
  • 用来表示生活中的关系

XML的语法

  • XML的文档声明

创建一个文件,后缀名为 .XML
如果要写XML,第一步必须要写一个文档声明(写了文档声明之后,才能写xml的内容)
属性:
version : 1.0 和 1.1 ,但是我们只用1.0 因为1.1不向下兼容
encoding : xml编码 gbk utf-8 iso8859-1
standalone : 表示这个xml文档是否可以独立存在。

<?xml version="1.0" encoding="gbk"?>   // xml文档声明
  • XML的属性命名规范

一个xml中,只能有一个根标签,其他标签都在这个标签下面
xml中区分大小写
不能以下划线和数字作为开头
不能以xml 、Xml 、 XML开头
不能包含冒号和空格。

  • XML的注释

<!-- xml中的注释 —>
注意的是注释是不能嵌套的。
第一行第一列必须放文档声明,注释也不能放在第一行的第一列。

  • XML的特殊字符
符号xml转义字符
&& amp;
<& lt;
>& gt;
"& quot;
& apos;
  • XML的CDATA区

当文档主体中出现了大量的转义字符的时候,我们可以使用cdata区,可以直接进行转义,不需要用字符。
写法:
这就是 : <![CDATA[if(a < n){}]]>

  • XML的PI指令

可以在xml中设置css样式
写法: <?xml-stylesheet type="text/css" href="1.css"?>
但是对中文的标签样式不起作用

  • XML的约束

xml的约束一共有两种: DTD约束 和 schema约束

DTD快速入门

  1. 选创建一个文件,后缀名为 .dtd

书写步骤:
(1)看xml中有多少个元素,那就在dtd中先写多少个<!ELEMENT>
(2)判断元素是简单元素还是复杂元素
     - 简单元素: 即没有子元素    <!ELEMENT 元素名称 (子元素)>
     - 复杂元素 : 有子元素   <!ELEMENT 元素名称 (#PCDATA)>
(3)在xml中引入dtd文件 < !DOCTYPE 根元素 SYSTEM “dtd文件路径”>

//xml文件
<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE person SYSTEM "1.dtd">
<person>
	<name>骚包</name>
	<age>20</age>
</person>

// dtd文件
<!ELEMENT person (name,age)>
<!ELEMENT name (#PCDATA)>
<!ELEMENT age (#PCDATA)>

dtd文件的三种引用方式

(1)引入外部dtd文件
                              < !DOCTYPE 根元素 SYSTEM “dtd文件路径”>
(2) 使用内部dtd文件

<?xml version="1.0" encoding="UTF-8"?>
<!-- <!DOCTYPE person SYSTEM "1.dtd"> -->
<!DOCTYPE person [
	<!ELEMENT person (name,age)>
	<!ELEMENT name (#PCDATA)>
	<!ELEMENT age (#PCDATA)>
]>
<person>
	<name>骚包</name>
	<age>20</age>
<!-- 	<a>aaa</a> -->
</person>

(3)使用外部的dtd文件(网络上的一些dtd文件)
< !DOCTYPE 根元素 PUBLIC “dtd名称” “dtd文档对象URL” >
后面学习的框架struct2 使用配置文件 使用外部dtd文件

使用dtd来定义元素

  • 语法格式:<!ELEMENT 元素名称 约束>

简单元素定义:
(1) (#PCDATA) : 约束name是字符串类型
(2)EMPTY : 元素为空 (没有内容)
(3)ANY : 任意
复杂元素定义:
(1)<!ELEMENT person (name,age,sex)> 子元素只能出现一次
(2)<!ELEMENT person (name+,age?,sex*)>
          + 号 : 一次或者多次
          ? 号 : 零次或者一次
          * 号 : 零次或者多次
(3)<!ELEMENT person (name | age | sex)> “ | ” : 表示这么多中只能出现其中一个

使用dtd来定义属性


语法:<!ATTLIST 元素名称
	 		属性名称	属性类型	属性的约束
	  >
属性的类型
	 - CDATA : 字符串
	 - 枚举 : 表示只能在一定范围内它能出现的值,但是每次只能出现其中的一个。
	 			**(aa|bb|cc)
	 			** 红绿灯效果
	 - ID : 只能以字母和下划线开头
属性的约束
	 - #REQUIRED : 属性必须存在
	 - #IMPLIED : 属性可有可无
	 - #FIXED : 表示一个固定值 #FIXED “aaa” 
	 		-  表示属性的值必须是aaa
	 - 直接值 : 默认值
实体的定义 :
	 -  <!ENTITY npos " ">
			 调用 &npos; 就可以直接输出空格。
	 - 注意点:实体的定义需要写在内部引用里面。如果写在外部的dtd里面,在某些浏览器里面下,内容可能不能用。

xml解析的介绍

xml是标记型文档
js使用dom解析标记型文档?
	- 根据html中层级结构,在内存中分配一个属性的结构,把html中的标签,属性和文本都封装成对象;
	- document对象、element对象、属性对象、文本对象、Node节点对象。

xml的解析方式: dom 和 sax

dom解析xml
------ 根据xml中的层级结构,在内存中分配一个树形结构,即把xml中的每一个部分封装都封装成对象。
缺点: 但是使用dom方式进行解析xml的时候,如果文件过大,就可能造成内存的溢出。
优点: 很方便进行增删改操作。

sax解析xml
采用事件驱动,边读边解析。
------ 从上到下,一行一行的解析,解析到某一个对象,把对象的名称返回。
缺点: 使用sax方式进行解析,不能进行增删改操作。
优点: 不会造成内存溢出,方便实现查询,

  • 想要解析xml,我们便需要一个解析器,
  • 不同公司和组织呢,提供了 针对 dom 和 sax 当时的解析器,通过api的方式提供。
  • sun公司针对dom和sax提供了解析器 ----- jaxp
  • dom4j组织,针对dom和sax方式提供了解析器 ----- dom4j (实际开发中使用最多的一种解析器。包含了jdom)
  • jdom组织, 针对dom和sax方式提供了解析器 ------ jdom

JAXP的API使用

  • jaxp是 java se 中的一部分。
  • jaxp解析器在 javax.xml.parsers 包下面。
  • 四个类,分别针对dom和sax解析器的类
  • --------- DOM :
  • ------------------ DocumentBuilder : 解析器类
  • ------------------ DocumentBuilderFactory : 解析器工厂类
  • --------- SAX:
  • ------------------ SAXparser: 解析器类
  • ------------------ SAXparserFactory : 解析器工厂类

使用JAXP实现查询

  • 给定初始xml文件
<?xml version="1.0" encoding="UTF-8"?>
<person>
	<p1>
		<name>张三</name>
		<age>20</age>
	</p1>
	<p1>
		<name>李四</name>
		<age>30</age>
	</p1>
</person>
  • 查询xml中的所有name元素的值
package cn.itcast.jaxptest;

import org.w3c.dom.Document;
import org.w3c.dom.Node;
import org.w3c.dom.NodeList;

import javax.xml.parsers.DocumentBuilder;
import javax.xml.parsers.DocumentBuilderFactory;

/**
 * @program: Test
 * @description:
 * @author: 作者
 * @create: 2021-05-17 10:38
 */
public class TestJaxp {
    public static void main(String[] args) throws Exception{
        // 查询所有的name元素的值
        /**
         *  1、创建解析器工厂
         *  2、根据解析器工厂创建解析器
         *  3、解析xml返回document
         *  4、得到所有的name元素
         *  5、返回集合,遍历集合,返回得到的每一个name元素
         */
        // 1.创建解析器工厂
        DocumentBuilderFactory builderFactory = DocumentBuilderFactory.newInstance();
        // 2.创建解析器
        DocumentBuilder builder = builderFactory.newDocumentBuilder();
        // 3.解析xml返回document
        Document document = builder.parse("XmlTest/src/person.xml");
        // 4.得到所有的name元素
        NodeList list = document.getElementsByTagName("name");
        // 遍历集合
        for(int i=0;i<list.getLength();i++){
            Node name1 = list.item(i);  // 得到每一个name元素
            String s = name1.getTextContent();
            System.out.println(s);
        }
    }
}
  • 修改添加xml文件
    // 对p1进行添加一个sex标签
    public  static  void addSex() throws Exception{
        DocumentBuilderFactory builderFactory = DocumentBuilderFactory.newInstance();
        DocumentBuilder builder = builderFactory.newDocumentBuilder();
        Document document = builder.parse("XmlTest/src/person.xml");
        // 得到p1
        NodeList list = document.getElementsByTagName("p1");
        // 得到第一个p1
        Node node = list.item(0);
        // 创建标签
        Element sex1 = document.createElement("sex");
        // 创建文本
        Text text1 = document.createTextNode("女");
        // 把文本1添加到标签下
        sex1.appendChild(text1);
        // 把sex1添加到p1下面去。
        node.appendChild(sex1);
        // 回写xml

        TransformerFactory transformerFactory = TransformerFactory.newInstance();
        Transformer transformer = transformerFactory.newTransformer();
        transformer.transform(new DOMSource(document) , new StreamResult("XmlTest/src/person.xml"));
    }
  • 使用jaxp修改节点
    // 对p1下面的节点sex进行修改成男
    public static void modifySex() throws Exception{
        DocumentBuilderFactory  builderFactory = DocumentBuilderFactory.newInstance();
        DocumentBuilder builder = builderFactory.newDocumentBuilder();
        Document document = builder.parse("XmlTest/src/person.xml");

        // 获得节点并且修改
        Node sex1 = document.getElementsByTagName("sex").item(0);
        sex1.setTextContent("男");

        // 回写
        TransformerFactory transformerFactory = TransformerFactory.newInstance();
        Transformer transformer = transformerFactory.newTransformer();
        transformer.transform(new DOMSource(document) , new StreamResult("XmlTest/src/person.xml"));
    }
  • 使用JAXP遍历xml中所有的标签
    // 打印所有的标签
    public static void listElement() throws  Exception {
        // 获得dom解析器
        DocumentBuilderFactory builderFactory = DocumentBuilderFactory.newInstance();
        DocumentBuilder builder = builderFactory.newDocumentBuilder();
        Document document = builder.parse("XmlTest/src/person.xml");

        //进行递归调用
        list1(document);
    }

    private static void list1(Node node) {
        // 判断是否是元素类型
        if(node.getNodeType() == node.ELEMENT_NODE){
            System.out.println(node.getNodeName());
        }

        NodeList list = node.getChildNodes();
        for(int i=0;i<list.getLength();i++){
            list1(list.item(i));
        }
    }

Schema约束

  • 完全符合xml中的语法,在xml中,只能使用一个dtd约束,但是可以使用多个schema约束。
  • dtd约束的支持的数据类只能是string类型,但是我们的schema约束可以有多个数据类型。
  • schema语法更加的复杂,不好学习。
  • schema文件后缀名为.xsd

创建schema文件

(1)、看xml文件里面有多少个元素
有多少个元素就写多少个 < element > 标签。
(2)、看开始的是简单元素还是复杂元素
如果是复杂元素,那就要这样写,然后简单元素存放在复杂元素下方

<?xml version="1.0" encoding="UTF-8" ?>
<schema
        xmlns="http://www.w3.org/2001/XMLSchema"
        targetNamespace="http://www.itcast.cn//20210519"
        elementFormDefault="qualified"
>
    <element name="person">
        <complexType>
            <sequence>
                <element name="name" type="string"/>
                <element name="age" type="int"/>
            </sequence>
        </complexType>
    </element>

</schema>

(4)、在xml文件中,引入schema约束文件。

<?xml version="1.0" encoding="UTF-8" ?>
<schema
        xmlns="http://www.w3.org/2001/XMLSchema"
        targetNamespace="http://www.itcast.cn//20210519"
        elementFormDefault="qualified"
>
    <element name="person">
        <complexType>
            <sequence>
                <element name="name" type="string"/>
                <element name="age" type="int"/>
            </sequence>
        </complexType>
    </element>

</schema>

schema约束属性

<sequence>  表示元素必须按照顺序出现。
<all> 		表示元素只能出现一次。
<choice> 	表示元素只能出现其中的一个
maxOccurs = "unbounded" 表示该简单元素可以出现无数次。
<any> 		表示可以出现任意元素。

元素属性的定义:
            <attribute name="id1" type="int" use="required" />

sax解析xml文件过程

当解析到开始标签的时候,会自动执行startElement方法,参数qName:返回标签名称。
当解析到文本内容的时候,执行characters方法,通过string构造器返回内容
当解析到结束标签的时候,执行endElement方法,通过qName,返回标签名称。

使用JAXP的sax方式进行解析xml文件

  • sax不能实现增删改操作。只能进行查询操作。
  • 打印出整个文档。
public class TestSax {
    public static void main(String[] args) throws Exception{
        /**
         * 1、创建一个解析器工厂
         * 2、创建解析器
         * 3、执行parse方法
         *
         * 4、需要自己创建一个类,来继承DefaultHandler
         * 5、重写类里面的那个三个方法。
         */
        SAXParserFactory saxParserFactory = SAXParserFactory.newInstance();
        SAXParser saxParser = saxParserFactory.newSAXParser();
        saxParser.parse("XmlTest/src/p1.xml",new MyDefault1());
    }
}
class MyDefault1 extends DefaultHandler {
    @Override
    public void startElement(String uri, String localName, String qName, Attributes attributes) throws SAXException {
        //super.startElement(uri, localName, qName, attributes);
        System.out.print("<" + qName + ">");
    }

    @Override
    public void endElement(String uri, String localName, String qName) throws SAXException {
        //super.endElement(uri, localName, qName);
        System.out.print("</" + qName + ">");
    }

    @Override
    public void characters(char[] ch, int start, int length) throws SAXException {
        //super.characters(ch, start, length);
        System.out.print(new String(ch,start,length));
    }
}
  • 通过重写里面的主要的三个方法,就可以打印出整个文档了。
  • 打印所有的name标签内容
public class MyDefault2 extends DefaultHandler {
    boolean flag = false;
    @Override
    public void startElement(String uri, String localName, String qName, Attributes attributes) throws SAXException {
        flag = qName.equals("name");
    }

    @Override
    public void endElement(String uri, String localName, String qName) throws SAXException {
       flag = false;
    }

    @Override
    public void characters(char[] ch, int start, int length) throws SAXException {
        if(flag) System.out.println(new String(ch,start,length));
    }
}

使用 dom4j 来解析xml

  • 先下载好dom4j jar包,然后导入
  • 然后学习里面的api使用,然后我们来试试查询xml中所有内容。
public class testDom4j {
    public static void main(String[] args) throws Exception{
        /**
         * 1、创建解析器
         * 2、得到document
         * 3、得到根节点
         *
         * 4、得到p1
         * 5、得到p1下面的name
         * 6、得到name的值
         */
        SAXReader saxReader = new SAXReader();
        Document document = saxReader.read("XmlTest/src/p1.xml");
        Element root = document.getRootElement();

        // 得到p1
        List<Element> list = root.elements("p1");
        // 遍历list
        for(Element element : list){
            Element name1 = element.element("name");
            System.out.println(name1.getText());
        }
    }
}
  • 得到第二name里面的值
public class testDom4j {
    public static void main(String[] args) throws Exception{
        /**
         * 1、创建解析器
         * 2、得到document
         * 3、得到根节点
         *
         * 4、得到p1
         * 5、得到p1下面的name
         * 6、得到name的值
         */
        SAXReader saxReader = new SAXReader();
        Document document = saxReader.read("XmlTest/src/p1.xml");
        Element root = document.getRootElement();

        // 得到p1
        List<Element> list = root.elements("p1");

        Element p2 = list.get(1);
        Element name2 = p2.element("name");
        System.out.println(name2.getText());
    }
}

使用dom4j实现添加操作

    // 向xml文件中添加sex标签
    public static void addSex() throws Exception{
        /**
         * 1、创建解析器
         * 2、得到document
         * 3、得到根节点
         *
         * 4、获取第一个p1标签
         * 5、在p1下面添加元素
         * 6、在添加完成以后的元素下面添加文字。
         * 7、回写xml
         */

        SAXReader saxReader = new SAXReader();
        Document document = saxReader.read("XmlTest/src/p1.xml");
        Element root = document.getRootElement();

        Element p1 = root.element("p1");
        Element sex1 = p1.addElement("sex");
        sex1.setText("女");

        // 回写xml
        OutputFormat format = OutputFormat.createPrettyPrint();  // 可以有缩进的效果
        XMLWriter xmlWriter = new XMLWriter(new FileOutputStream("XmlTest/src/p1.xml"), format);
        xmlWriter.write(document);
        xmlWriter.close();
    }
  • 回写很重要哦,还有出现流文件要记得关闭哦;

在特定位置进行添加元素

    // 在第一个p1标签里面的age标签前进行添加<school>标签
    public static void addschool() throws  Exception{
        SAXReader saxReader   = new SAXReader();
        Document document = saxReader.read("XmlTest/src/p1.xml");
        Element root = document.getRootElement();
        Element p1 = root.element("p1");
        List<Element> list = p1.elements();
        Element school = DocumentHelper.createElement("school");
        school.setText("湖南警察学院");
        list.add(0,school);

        // 回写
        OutputFormat format = OutputFormat.createPrettyPrint();
        XMLWriter xmlWriter = new XMLWriter(new FileOutputStream("XmlTest/src/p1.xml"),format);
        xmlWriter.write(document);
        xmlWriter.close();
    }

对常用方法的利用进行封装

public class Dom4jUtils {
    // 路径的封装
    public static final String PATH = "XmlTest/src/p1.xml" ;

    // 返回document
    public static Document getDocument(String s)  {
        try {
            SAXReader saxReader = new SAXReader();
            return (Document) saxReader.read(s);
        }catch (Exception e){
            e.printStackTrace();
        }
        return null;
    }

    // 回写xml
    public static void xmlWriters( String path , Document document) {
        try{
            OutputFormat format = OutputFormat.createPrettyPrint();
            XMLWriter xmlWriter = new XMLWriter(new FileOutputStream(path),format);
            xmlWriter.write(document);
            xmlWriter.close();
        }catch (Exception e){
            e.printStackTrace();
        }
    }
}

使用dom4j对xml文件进行修改

    // 修改age里面的值。
    public static void modify() throws Exception {
        Document document = Dom4jUtils.getDocument(Dom4jUtils.PATH);
        Element root = document.getRootElement();
        Element p1 = root.element("p1");
        Element age1 = p1.element("age");
        age1.setText("66");
        // 对xml进行回写操作
        Dom4jUtils.xmlWriters(Dom4jUtils.PATH , document);
    }

使用dom4j对xml进行删除操作

    // 删除school 标签
    public static void delSchool() throws Exception {
        // 获得document
        Document document = Dom4jUtils.getDocument(Dom4jUtils.PATH);
        // 得到根元素
        Element root = document.getRootElement();
        Element p1 = root.element("p1");
        p1.remove(p1.element("school"));
        // 回写 xml
        Dom4jUtils.xmlWriters(Dom4jUtils.PATH , document);
    }

使用dom4j来获取标签的属性值

    // 获取属性值
    public static void getValues() throws Exception {
        Document document = Dom4jUtils.getDocument(Dom4jUtils.PATH);
        Element root = document.getRootElement();
        Element p1 = root.element("p1");
        System.out.println(p1.attributeValue("id1"));
    }

使用dom4j来支持xpath操作

  • 直接进行获取某个元素
  • 第一种形式 : /AAA/DDD/BBB : 表示一层一层,A下面是D,D下面是B
  • 第二种://BBB 表示和这个名称相同,表示名称是BBB,都可以得到。
  • 第三种:/* 表示所有元素。
  • 第四种: /BBB[0] 表示第一个bbb元素。
  • 第五种: //BBB[@id] : 表示只要BBB元素上面有id属性,都得到。
  • 第六种://BBB[@id=“b1”] : 表示名称是BBB,在BBB上面有id属性。并且这个id属性是b1

那么我们想要用它的话呢,需要先导入支持xpath的jar包。
然后就可使用了

public class testXpath {
    public static void main(String[] args) throws Exception {
        name1();
    }

    // 使用xpath获取xml中第一个name的值
    public static void name1() throws Exception{
        Document document = Dom4jUtils.getDocument(Dom4jUtils.PATH);
        assert document != null;
        Node node = document.selectSingleNode("//p1[@id1='aaa']/name");
        if(node != null) System.out.println(node.getText());

    }

    // 查询xml中所有name的值
    public static void allName() throws Exception {
        Document document = Dom4jUtils.getDocument(Dom4jUtils.PATH);
        assert document != null;
        List<Node> list = document.selectNodes("//name");
        for(Node node : list){
            System.out.println(node.getText());
        }
    }
}

学生管理系统实战

  • 我们先来建立原始的xml文件
<?xml version="1.0" encoding="UTF-8"?>

<student> 
  <stu> 
    <id>100</id>  
    <name>张三</name>  
    <age>20</age> 
  </stu>  
  <stu> 
    <id>101</id>  
    <name>李四</name>  
    <age>30</age> 
  </stu>  
</student>
  • 然后我们通过jaxp进行实现他的增删查改
package service;

import com.sun.javafx.collections.ElementObservableListDecorator;
import org.dom4j.Document;
import org.dom4j.Element;
import org.dom4j.Node;
import org.dom4j.io.OutputFormat;
import org.dom4j.io.SAXReader;
import org.dom4j.io.XMLWriter;
import org.w3c.dom.NodeList;
import vo.Student;

import java.io.FileOutputStream;
import java.util.List;

/**
 * @program: Test
 * @description:
 * @author: 作者
 * @create: 2021-05-20 20:54
 */
public class stuService {
    public static void main(String[] args) throws Exception{
        //addStu(new Student("102","王老五","40"));
        //delStu("102");
        Student ans = getStu("100");
        System.out.println(ans.getId());
        System.out.println(ans.getName());
        System.out.println(ans.getAge());
    }
    // 增加
    public static void addStu(Student student) throws Exception{
        SAXReader saxReader = new SAXReader();
        Document document = saxReader.read("student/src/student.xml");
        Element root = document.getRootElement();
        Element stu = root.addElement("stu");
        Element id1 = stu.addElement("id");
        Element name1 = stu.addElement("name");
        Element age1 = stu.addElement("age");
        id1.setText(student.getId());
        name1.setText(student.getName());
        age1.setText(student.getAge());
        // 回写xml
        OutputFormat format = OutputFormat.createPrettyPrint();
        XMLWriter xmlWriter = new XMLWriter(new FileOutputStream("student/src/student.xml"),format);
        xmlWriter.write(document);
        xmlWriter.close();
    }

    // 删除
    public static void delStu(String id) throws Exception {
        Document document = Dom4jUtils.getDocument(Dom4jUtils.PATH);
        Element root = document.getRootElement();
        assert document != null;
        List<Node> list = document.selectNodes("//id");
        for(Node node : list){
            if(node.getText().equals(id)){
                root.remove(node.getParent());
                break;
            }
        }
        // 回写xml
        Dom4jUtils.xmlWriters(Dom4jUtils.PATH,document);
    }

    // 查询
    public static Student getStu(String id) throws Exception {
        Document document = Dom4jUtils.getDocument(Dom4jUtils.PATH);
        assert document != null;
        Element root = document.getRootElement();
        List<Node> list = document.selectNodes("//id");
        for(Node node : list){
            if(node.getText().equals(id)){
                String name = node.getParent().element("name").getText();
                String age = node.getParent().element("age").getText();
                return new Student(id,name,age);
            }
        }
        return null;
    }
}

欧拉,到这里基本上xml就结束拉。告辞拉

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

木木不会

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值