XML:可扩展标记语言

XML:可扩展标记语言

主要内容

  • XML介绍
  • DTD
  • XSD
  • DOM解析
  • SAX解析

学习目标

知识点 要求
XML介绍 掌握
DTD 掌握
XSD 掌握
DOM解析 掌握
SAX解析 掌握

一、XML介绍

1. 简介

XML(Extensible Markup Language)可扩展标记语言。严格区分大小写。

2. XML和HTML

XML是用来传输和存储数据的。

XML 多用在框架的配置文件中。

XML 大多平台都支持,所以可以实现跨平台数据传输。

HTML 是用来显示数据的。

3. 语法

<元素名 属性名="属性值">文本内容</元素名>

前后元素名相同, 元素名自定义。

每个元素可以有0到多个属性,属性名自定义。

文本内容表示文字。

支持嵌套结构。

结束时元素名前有 /。

4. 语法要求

XML的语法和HTML语法是差不多的,但是比HTML要求更加严格。

​ 1. 元素正确嵌套

​ 2. XML文件的第一行必须是xml声明

​ 3. 只能有一个根节点

​ 4. 严格区分大小写

​ 5. 结束标签必须包含/

​ 6. 属性值必须被""包围起来

​ 7. XML认为换行标记也属于文本节点

​ 8. <!-- --> 注释。有的非官方资料认为这是注释节点。

5. 特殊字符

5.1 实体符号
5.2 转义标签

<![CDATA[

要显示的字符

]]>

二、小节实战案例 - 编写XML文件

1. 需求

项目根路径下创建product.xml并存储下面信息。

根节点叫做products,里面包含3个product元素。每个元素里面又包含下面的元素及文本内容

id 名称(name) 单价(price) 颜色(color) 尺寸(size) 库存(num)
P001 蜘蛛王皮鞋 268 黑色 42 500
P002 ThinkPad x240 5678 黑色 12 50
P003 WD移动硬盘 568 蓝色 5 1000

2. 实现

xml 复制代码
<?xml version="1.0" encoding="utf-8" ?> <!-- xml的文档声明 -->
<products>
  <product>
    <id>P001</id>
    <name>蜘蛛王皮鞋</name>
    <price>268</price>
    <color>黑色</color>
    <size>42</size>
    <num>500</num>
  </product>
  <!-- ... -->
</products>

三、DTD

1. 简介

DTD(Document Type Definition)文档类型定义。

即约束XML文件中可以包含哪些元素、哪些属性、及元素个数和元素之间的关系和元素的顺序。

在包含DTD的XML文件中,如果XML内容不满足DTD要求,会提示错误。

2. 分类

DTD的三种分类:

​ 1. 内部DTD

​ 2. 外部DTD

​ 3. 公共DTD

2.1 内部DTD

直接在XML中编写DTD内容。不推荐。

  1. <!ELEMENT 元素名 (包含内容)> 内容可以是其他标签,也可以是#PCDATA文本内容。

  2. <!ATTLIST 元素名 属性名 CDATA 内容控制> 定义属性

  3. 内容控制可取值:

​ 1. #REQUIRED 必须有这个属性

​ 2. #IMPLIED 可以有也可以没有

​ 3. #FIXED "内容" 必须取固定值

  1. (name,age,score) 表示顺序必须是先name,后age,然后score

  2. student+ 表示student至少出现一次。括号内容的元素名都可以跟下面符号

​ 1. ?表示子元素出现0次到1次 (最多出现一次)

​ 2. + 表示子元素至少出现一次 (至少出现一次 )

​ 3. *表示子元素可以出现0到多次 (任意)

xml 复制代码
<?xml version="1.0" encoding="UTF-8" ?> <!-- 声明xml文档头 -->
<!-- 内部DTD约束 -->
<!--
    !DOCTYPE: 固定语法 文档类型
    students: 自定义根标签名字
    []: 存放子标签
    ELEMENT: 元素(标签)
       #PCDATA:元素是字符串类型#PCDATA(不能再有子元素,也不能为空)
    DTD中标签的顺序就是日后使用的顺序, 不允许改变
-->
<!DOCTYPE students[
        <!-- 标签 -->
        <!--
            (student): 只能有一对student标签
            (student?): 0~1次
            (student+): 至少1次
            (student*): 0~多次
        -->
        <!ELEMENT students (student*)>
        <!ELEMENT student (name, age, sex)>
        <!ELEMENT name (#PCDATA)>
        <!ELEMENT age (#PCDATA)>
        <!ELEMENT sex (#PCDATA)>
        <!-- 属性 -->
        <!--
            ATTLIST: 属性
            student: 哪个标签指定属性
            id: 指定的属性名
            CDATA: 属性控制
                #REQUIRED: 必须有
                #FIXED "值": 固定值
                #IMPLIED: 可有可无
        -->
        <!ATTLIST student id CDATA #REQUIRED>
        <!ATTLIST name class CDATA #FIXED "qwe">
        <!ATTLIST age test CDATA #IMPLIED>
        ]>

<students>
  <student id="aa">
    <name class="qwe">张三</name>
    <age test="aaa">18</age>
    <sex>男</sex>
  </student>
</students>
2.2 外部DTD

外部DTD是我们自己编写的DTD文件。通过引入方式引入DTD。

在外部创建一个xxx.dtd文件,文件内容和内部dtd [ ] 中的内容相同。

  1. 新建dtd文件
dtd 复制代码
<!ELEMENT students (student*)>
<!ELEMENT student (name, age, sex)>
<!ELEMENT name (#PCDATA)>
<!ELEMENT age (#PCDATA)>
<!ELEMENT sex (#PCDATA)>
<!ATTLIST student id CDATA #REQUIRED>
<!ATTLIST name class CDATA #FIXED "qwe">
<!ATTLIST age test CDATA #IMPLIED>
  1. xml引入外部dtd文件
xml 复制代码
<?xml version="1.0" encoding="UTF-8" ?>
<!DOCTYPE students SYSTEM "aa.dtd">
<students>
  <student id="aa" >
    <name class="qwe">张三</name>
    <age test="aaa">18</age>
    <sex>男</sex>
  </student>
</students>
2.3 公共DTD

公共DTD是一些开源组织编写的DTD,并且已经发布到互联网中。

公共DTD语法:

<!DOCTYPE 根元素 PUBLIC "DTD标识名" "公用DTD的URI">

代码示例:

3. 总结

DTD是较简单的语法检查机制。整体语法较简单,功能较单一。

当需要对XML文件结构更新时,需要修改整个DTD文件,不够灵活。

四、XSD

1. 简介

XSD(XML Schema Definition )XML模式定义。

属于DTD的升级版。完美的解决了DTD使用时不易扩展问题,并且提供了更强大功能。

2. 定义XSD

新建xxx.xsd。

所有需要的元素、属性都需要被定义。

xml 复制代码
<!--
  声明xsd约束
 		aa: 自定义名称(随意)
  	schema: 约束(固定)
-->
<aa:schema xmlns:aa="http://www.w3.org/2001/XMLSchema">
  <!--
        aa:element: 标签
        name: 标签名
    -->
  <aa:element name="students">
    <!-- 必须设置为复杂类型 -->
    <aa:complexType>
      <!-- 在此标签中规范了 标签的顺序 -->
      <aa:sequence>
        <!-- 引用其他标签 -->
        <!-- maxOccurs: 指定可以有多少个标签 -->
        <aa:element ref="student" maxOccurs="2"/>
      </aa:sequence>
    </aa:complexType>
  </aa:element>
  <aa:element name="student">
    <!-- 复杂类型可以指定 包含的标签  属性 -->
    <aa:complexType>
      <aa:sequence>
        <!-- type: 值的类型 -->
        <aa:element name="name" type="aa:string"/>
        <aa:element name="age" type="aa:int"/>
        <aa:element name="sex" type="aa:boolean"/>
      </aa:sequence>
      <!--
                use: 属性的设置
                    required : 必须存在
                    prohibited: 禁用
                    optional: 可选的
                fixed="值": 固定值
            -->
      <aa:attribute name="id" use="optional" fixed="aa"/>
    </aa:complexType>
  </aa:element>
</aa:schema>

3. 引用xsd

xml 复制代码
<?xml version="1.0" encoding="UTF-8" ?>
<students xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
          xsi:noNamespaceSchemaLocation="s.xsd">
  <student id="aa">
    <name></name>
    <age>11</age>
    <sex>false</sex>
  </student>
</students>

五、XML 解析

1. 简介

在Java中提供了两种XML解析方式:DOM、SAX。

2. DOM解析

Document Object Model 文档对象模型。把XML文件一次性加载到内存中,并转换为树状模型。然后一个节点一个节点的解析,这种解析方式效率较高,但是比较消耗内存,适用于小型XML文档。

3. SAX

SAX(Simple API for XML)解析:是基于事件的解析,它是为了解决DOM解析的资源耗费而出现的。SAX在解析一份XML文档时,会依次出发文档开始、元素开始、元素结束、文档结束等事件,应用程序通过监听解析过程中所触发的事件即可获取XML文档的内容。该方式不需要事先调入整个文档,优势是占用资源少,内存消耗小,一般在解析数据量较大的文档是采用该方式。

六、DOM解析

1. 简介

DOM解析所有API都是org.w3c包中。

使用DOM操作XML按照标准树状结构一层一层解析。

解析器是基于工厂设计模式的。当获取到文档对象后每个元素都是一个节点,然后操作节点对象。

在DOM解析时,每个换行符都是一个文本节点,所以一定要过滤掉换行。

2. 代码示例

以上面的students作为xml进行解析。

已知XML文件就三层结构,所以直接使用循环进行解析。如果XML文档结构比较深,此处需要使用递归。

java 复制代码
public class TestDOM {
  public static void main(String[] args) throws Exception {
    parse();
  }
  //使用DOM解析XML
  public static void parse() throws ParserConfigurationException, IOException, SAXException {
    //1.获取document构建 工厂对象
    DocumentBuilderFactory dbf = DocumentBuilderFactory.newInstance();
    //2.根据文档构建工厂获取文档构建对象
    /*
     * 将xml变为document
     * 手动的创建document
     * */
    DocumentBuilder db = dbf.newDocumentBuilder();
    //3.使用文档构建对象, 将xml解析为document对象
    Document document = db.parse(new File("stu.xml"));
    //4.根据标签名获取根标签
    NodeList rootList = document.getElementsByTagName("students");
    //5.xml中仅会存在一个根标签, 获取这个根标签
    Node root = rootList.item(0);
    System.out.println("根节点名称: " + root.getNodeName());
    //6.获取标签所有的直接子节点
    NodeList childNodes = root.getChildNodes();
    for (int i = 0; i < childNodes.getLength(); i++) {
      //7.获取每一个子节点
      /*
       * getNodeType(): 结点类型, 常量
       *           1: 标签结点
       *           2: 属性结点
       *           3: 文本结点
       * */
      Node item = childNodes.item(i);
      if (item.getNodeType() == Node.ELEMENT_NODE) {
        System.out.println(" 子节点名称: " + item.getNodeName());
        //8.获取该结点的所有子节点
        NodeList childNodes1 = item.getChildNodes();
        for (int j = 0; j < childNodes1.getLength(); j++) {
          Node item1 = childNodes1.item(j);
          if (item1.getNodeType() == Node.ELEMENT_NODE) {
            System.out.println("   子节点名称: " + item1.getNodeName() + " : " + item1.getTextContent());
          }
        }
      }
    }
  }
}

七、使用DOM生成XML

1. 简介

DOM生成XML时主要是创建节点。然后把节点添加到上层节点。

2. 代码示例

java 复制代码
public class TestDOM {
  public static void main(String[] args) throws Exception {
    transform();
  }
  //先构建文档, 再将文档变为xml
  public static void transform() throws ParserConfigurationException, TransformerException, FileNotFoundException {
    //1.获取文档构建器工厂对象
    DocumentBuilderFactory dbf = DocumentBuilderFactory.newInstance();
    //2.构建器工厂对象 获取 构建器对象
    DocumentBuilder db = dbf.newDocumentBuilder();
    //3.创建文档对象
    Document document = db.newDocument();
    //4.创建teachers标签
    Element teachers = document.createElement("teachers");
    //5.创建teacher标签
    Element teacher = document.createElement("teacher");
    teacher.setAttribute("id", "tea"); //设置属性
    //6.创建name标签
    Element name = document.createElement("name");
    name.setAttribute("class", "na"); //设置属性
    name.setTextContent("zs");
    //7.创建age标签
    Element age = document.createElement("age");
    age.setTextContent("18");
    //8.创建sex标签
    Element sex = document.createElement("sex");
    sex.setTextContent("男");

    //9.设置标签之间的关系
    /* 添加teacher的子标签 */
    teacher.appendChild(name);
    teacher.appendChild(age);
    teacher.appendChild(sex);
    /* 添加teachers的子标签 */
    teachers.appendChild(teacher);
    /* 添加文档的子标签 */
    document.appendChild(teachers);
    /* 设置为独立的xml */
    document.setXmlStandalone(true);

    //10.将document对象变为xml
    //10.1 创建转换器工厂对象
    TransformerFactory tff = TransformerFactory.newInstance();
    //10.1 根据转换器工厂对象 获取 转换器
    Transformer tf = tff.newTransformer();
    tf.setOutputProperty(OutputKeys.INDENT, "yes");
    tf.setOutputProperty("{http://xml.apache.org/xslt}indent-amount", "2");
    //10.3 将document转化为xml  通过流输出到指定的位置
    /*
     * 参数1: 指定document源
     * 参数2: 输出的位置
     * */
    tf.transform(new DOMSource(document), new StreamResult(new FileOutputStream("teacher.xml")));
  }
}

八、SAX解析

1. 简介

SAX解析是基于事件模型完成的。所有的API都在org.xml中。

SAX解析时也会识别换行为文本节点,这个坑一定躲避。

2. 代码示例

java 复制代码
public class TestSAX {
  public static void main(String[] args) throws Exception {
    parse();
  }
  public static void parse() throws Exception {
    //1.SAX解析器工厂对象
    SAXParserFactory spf = SAXParserFactory.newInstance();
    //2.基于工厂对象获取解析器对象
    SAXParser sp = spf.newSAXParser();
    //3.使用解析器解析xml
    sp.parse(new File("java_day13/teacher.xml"), new MyHandler());
  }

  public class MyHandler extends DefaultHandler {
    String name = null;

    @Override
    public void startDocument() throws SAXException {
      System.out.println("文档开始解析");
    }

    @Override
    public void startElement(String uri, String localName, String qName, Attributes attributes) throws SAXException {
      System.out.println("开始解析, 标签名: " + qName);
      name = qName;
    }

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

    @Override
    public void endElement(String uri, String localName, String qName) throws SAXException {
      System.out.println("解析结束, 标签名: " + qName);
    }

    @Override
    public void endDocument() throws SAXException {
      System.out.println("文档解析结束");
    }
  }

}

九、SAX 生成

1. 简介

SAX 生成XML 和手写XML比较相似。

也是在调用5个操作方法。

2. 代码示例

java 复制代码
public class TestSAX {
  public static void main(String[] args) throws Exception {
    parse();
  }
  public void transfom() throws TransformerConfigurationException, FileNotFoundException, SAXException {
    //1.创建转换器工厂
    SAXTransformerFactory stff = (SAXTransformerFactory) SAXTransformerFactory.newInstance();
    //2.根据工厂获取转换器
    /*
     * 传输
     * 创建xml
     * */
    TransformerHandler th = stff.newTransformerHandler();
    
    Transformer transformer = th.getTransformer();
    transformer.setOutputProperty(OutputKeys.INDENT, "yes");
    transformer.setOutputProperty(OutputKeys.ENCODING, "utf-8");
    transformer.setOutputProperty("{http://xml.apache.org/xslt}indent-amount", "2");
    
    th.setResult(new StreamResult(new FileOutputStream("stu.xml")));
    th.startElement(null, null, "students", null);
    AttributesImpl attributes = new AttributesImpl();
    attributes.addAttribute(null, null, "id", null, "aa");
    th.startElement(null, null, "student", attributes);
    th.startElement(null, null, "name", null);
    char[] chars = "zs".toCharArray();
    th.characters(chars, 0, chars.length);
    th.endElement(null, null, "name");
    th.startElement(null, null, "age", null);
    char[] chars1 = "19".toCharArray();
    th.characters(chars1, 0, chars1.length);
    th.endElement(null, null, "age");
    th.startElement(null, null, "sex", null);
    char[] chars2 = "男".toCharArray();
    th.characters(chars2, 0, chars2.length);
    th.endElement(null, null, "sex");
    th.endElement(null, null, "student");
    th.endElement(null, null, "students");
    th.endDocument();
  }
}

作业:

使用SAX | DOM 解析xml, 将解析xml的代码封装到一个方法中, 调用该方法返回一个对象(将xml解析的内容创建对象. 设置属性值, 返回对象)

xml 复制代码
<phone id="iph">
  <name>ls</name>
  <price>1999</price>
  <color>黑色</color>
</phone>

解析后:
	phone对象 属性值 name ls  price 1999 color 黑色
相关推荐
乐闻x1 分钟前
Vue.js 性能优化指南:掌握 keep-alive 的使用技巧
前端·vue.js·性能优化
好奇的菜鸟3 分钟前
Go语言中的引用类型:指针与传递机制
开发语言·后端·golang
一条晒干的咸魚3 分钟前
【Web前端】创建我的第一个 Web 表单
服务器·前端·javascript·json·对象·表单
所待.3837 分钟前
JavaEE之线程初阶(上)
java·java-ee
Winston Wood11 分钟前
Java线程池详解
java·线程池·多线程·性能
Alive~o.012 分钟前
Go语言进阶&依赖管理
开发语言·后端·golang
手握风云-15 分钟前
数据结构(Java版)第二期:包装类和泛型
java·开发语言·数据结构
许苑向上18 分钟前
Dubbo集成SpringBoot实现远程服务调用
spring boot·后端·dubbo
Amd79419 分钟前
Nuxt.js 应用中的 webpack:compiled 事件钩子
前端·webpack·开发·编译·nuxt.js·事件·钩子
东华果汁哥20 分钟前
【linux 免密登录】快速设置kafka01、kafka02、kafka03 三台机器免密登录
linux·运维·服务器