Java基础快速入门:XML配置、约束与解析

本文纲要

  1. XML 概述与优势
  2. XML基础语法
    标签规则
    文档结构
    特殊字符与CDATA
  3. XML约束
    DTD约束
    DTD语法(元素、属性)
    引入DTD的三种方式
    Schema约束
    SchemaDTD的区别
    Schema语法(元素、属性)
    引入Schema
  4. XML解析
    DOM解析思想
    dom4j解析实战

XML概述与优势

XML(eXtensible Markup Language,可扩展标记语言)是一种用于存储和传输数据的标记语言。它由W3C(万维网联盟)发布,广泛应用于Java项目的配置文件、数据交换等场景。

相比于传统的.properties配置文件,XML具有更好的可读性和可维护性,尤其当配置项较多时,结构化的标签能清晰地表达数据层次。

优势对比:

特性 properties 文件 XML 文件
结构 键值对,平铺 标签嵌套,层次化结构
可读性 配置项多时冗长 标签包围,直观,易于阅读
扩展性 一般 可自定义标签,扩展性强

例如下面这个 XML 配置片段,配置一个 Servlet 时十分清晰:

xml 复制代码
<servlet>
    <servlet-name>loginServlet</servlet-name>
    <servlet-class>com.example.LoginServlet</servlet-class>
</servlet>

当需要配置多个 Servlet 时,只需复制整个<servlet>块即可,维护与阅读都很方便。

XML基础语法

1 ) 标签规则

XML 由标签组成,标签名称可以自定义,但需要遵循以下规则:

  • 标签由尖括号和标识符组成,例如 <student>
  • 标签必须成对出现:开始标签 <name> 和结束标签 </name>
  • 特殊标签可以不成对,但必须有结束标记,例如 <address/>
  • 属性值必须用引号(单引号或双引号)括起来,例如 id="1"
  • 标签必须正确嵌套
    • 错误示例:<student><name>张三</student></name> (×)
    • 正确:<student><name>张三</name></student>

2 ) 文档结构

一个标准的 XML 文件包含以下部分:

xml 复制代码
<?xml version="1.0" encoding="UTF-8" ?>
<!--注释内容-->
<rootElement>
    <child attribute="value">文本内容</child>
</rootElement>

主要组成:

  1. 文档声明:必须在第一行第一列,不能有前导空格
    • version:必须写,固定为 "1.0"
    • encoding:可选,常用 UTF-8
    • standalone:可选,表示是否依赖其他 XML 文件(yes/no
  2. 根标签:整个文档有且仅有一个根标签
  3. 子标签:可任意嵌套

3 ) 特殊字符与CDATA区

若想在标签体中包含 <> 等特殊字符,需要使用预定义实体:

字符 实体引用
< &lt;
> &gt;
& &amp;
" &quot;
' '

例如:

xml 复制代码
<info>学生&lt; &gt; 的信息</info>

如果文本中包含大量特殊字符,逐一转义很麻烦,可以使用 CDATA区,其内容会被当作纯文本:

xml 复制代码
<message><![CDATA[内容 <<<<<< >>>>>>]]></message>

这样即使出现多个 <> 也不会报错。

示例代码(对应项目中的 student.xml 注释部分):

xml 复制代码
<!-- 使用转义字符 -->
<info>学生&lt; &gt;&gt;&gt;&gt;&gt;&gt;&gt; 的信息</info>
 
<!-- 使用CDATA区 -->
<message><![CDATA[内容 <<<<<< >>>>>>]]></message>

4 ) XML校验

编写完 XML 后,可以通过以下方式校验是否正确:

  • IDE 校验:IDEA 等开发工具会自动标红错误
  • 浏览器打开:正确显示可折叠的树形结构,错误时显示错误信息

XML约束

在实际项目中,XML 多作为配置文件,软件的解析代码是事先写好的。为了防止开发者随意定义标签而导致解析失败,需要使用约束技术 限定 XML 中可以使用的标签、属性等。

项目结构一览

最终项目包含 XML 示例、约束文件及解析代码,完整结构如下:

dir 复制代码
myxml/
├── libs/
│   └── dom4j-1.6.1.jar 
├── xml/
│   └── student.xml               # 解析目标文件 
├── dtdgrammar/
│   ├── person1.xml                # 引用DTD的XML 
│   └── persondtd.dtd              # DTD约束文件 
├── importdtd/
│   ├── person1.xml                # 引入本地DTD 
│   ├── person2.xml                # 内部定义DTD 
│   ├── person3.xml                # 引入网络DTD 
│   └── persondtd.dtd              # 公用DTD 
├── schemaprimer/
│   ├── person.xml                 # 引用Schema的XML 
│   └── person.xsd                 # Schema约束文件 
└── src/
    └── com/wb/xmlparse/
        ├── Student.java           # 实体类 
        └── XmlParse.java          # dom4j解析演示 

常用约束技术有两种:DTDSchema

1 ) DTD约束

1.1 DTD入门

DTD(Document Type Definition)通过定义元素和属性来约束 XML。

元素即标签,分为:

  • 简单元素 :不包含子元素,如 <name><age>
  • 复杂元素 :包含子元素,如 <persons><person>

定义元素格式:<!ELEMENT 元素名 (内容)>

简单元素内容写 (#PCDATA),表示字符串;复杂元素内容写子元素名。

示例:约束如下 XML

xml 复制代码
<persons>
    <person>
        <name>张三</name>
        <age>23</age>
    </person>
</persons>

对应的 DTD 文件 persondtd.dtd

dtd 复制代码
<!ELEMENT persons (person)>
<!ELEMENT person (name, age)>
<!ELEMENT name (#PCDATA)>
<!ELEMENT age (#PCDATA)>

说明:

  • persons 是复杂元素,包含 person
  • person 是复杂元素,包含 nameage(逗号表示顺序出现)
  • nameage 是简单元素,类型为 #PCDATA

1.2 引入DTD的三种方式

1.2.1 引入本地DTD:<!DOCTYPE 根标签名 SYSTEM "dtd文件路径">

xml 复制代码
<!DOCTYPE persons SYSTEM 'persondtd.dtd'>

1.2.2 在XML内部定义DTD

xml 复制代码
<!DOCTYPE persons [
    <!ELEMENT persons (person)>
    <!ELEMENT person (name, age)>
    <!ELEMENT name (#PCDATA)>
    <!ELEMENT age (#PCDATA)>
]>

1.2.3 引入网络DTD

xml 复制代码
<!DOCTYPE persons PUBLIC "dtd名称" "dtd文档的URL">

1.3 DTD语法规则

定义元素数量限定:

  • + :至少出现一次
  • * :零次或多次
  • ? :零次或一次
  • 不写:恰好一次
  • | :或,只能选一个

例如:

dtd 复制代码
<!ELEMENT persons (person+)>   <!-- person可多次出现 -->
<!ELEMENT person (name|age)>   <!-- name或age选其一 -->

定义属性

格式:<!ATTLIST 元素名 属性名 属性类型 约束>

  • 属性类型常用 CDATA(普通字符串)
  • 约束:
    • #REQUIRED :必填
    • #IMPLIED :可选
    • #FIXED "值" :固定值

示例:

dtd 复制代码
<!ATTLIST person id CDATA #REQUIRED>

表示 person 标签必须有 id 属性,属性值为字符串。

完整 DTD 案例(项目 dtdgrammar/persondtd.dtd):

dtd 复制代码
<!ELEMENT persons (person+)>
<!ELEMENT person (name,age)>
<!ELEMENT name (#PCDATA)>
<!ELEMENT age (#PCDATA)>
<!ATTLIST person id CDATA #REQUIRED>

对应 XML 必须写 id 属性:

xml 复制代码
<persons>
    <person id="001">
        <name>张三</name>
        <age>23</age>
    </person>
</persons>

2 ) Schema约束

2.1 SchemaDTD的区别

Schema 也是一种 XML 约束,相比 DTD 更强大:

对比项 DTD Schema
自身是否为XML
引用多个约束 不支持 支持,使用名称空间区分
数据类型 只有 #PCDATA 支持多种类型(string,int等)
后缀名 .dtd .xsd

重点:Schema 本身也是 XML 文件,它约束别人,同时也被别的 Schema 约束

2.2 编写Schema

以约束下面的 XML 为目标:

xml 复制代码
<persons>
    <person id="001">
        <name>张三</name>
        <age>23</age>
    </person>
</persons>

对应的 Schema 文件 person.xsd:

xml 复制代码
<?xml version="1.0" encoding="UTF-8" ?>
<schema 
    xmlns="http://www.w3.org/2001/XMLSchema"
    targetNamespace="http://www.wb.cn/javase"
    elementFormDefault="qualified"
<!--定义persons复杂元素-->
    <element name="persons">
        <complexType>
            <sequence>
                <!--定义person复杂元素-->
                <element name="person">
                    <complexType>
                        <sequence>
                            <!--定义name和age简单元素-->
                            <element name="name" type="string"></element>
                            <element name="age" type="string"></element>
                        </sequence>
                        <attribute name="id" type="string" use="required"></attribute>
                    </complexType>
                </element>
            </sequence>
        </complexType>
    </element>
</schema>

要点解析:

  • xmlns="http://www.w3.org/2001/XMLSchema" :表示当前文件是一个约束文件
  • targetNamespace :指定本约束的名称空间,供他人引用
  • elementFormDefault="qualified" :固定格式,表示本文件质量良好
  • <element>:定义元素,复杂元素用 <complexType> 包裹;简单元素用 type="string" 等指定类型
  • <sequence>:指示子元素必须按顺序出现
  • <attribute>:定义属性,use="required" 表示必填,optional 为可选

2.3 引入Schema

在 XML 的根标签中添加:

xml 复制代码
<persons 
    xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
    xmlns="http://www.wb.cn/javase"
    xsi:schemaLocation="http://www.wb.cn/javase person.xsd"
<!-- 内容 -->
</persons>

说明:

  • xmlns:xsi:声明本 XML 是一个被 Schema 约束的实例
  • xmlns="...":引入约束文件的名称空间(即 targetNamespace
  • xsi:schemaLocation:内容为"名称空间 URI 空格 xsd 文件路径",告诉解析器从哪里找约束文件

Mermaid 流程图 - Schema约束作用机制:
#mermaid-svg-qYGd4FHsErSHwfKl{font-family:"trebuchet ms",verdana,arial,sans-serif;font-size:16px;fill:#333;}@keyframes edge-animation-frame{from{stroke-dashoffset:0;}}@keyframes dash{to{stroke-dashoffset:0;}}#mermaid-svg-qYGd4FHsErSHwfKl .edge-animation-slow{stroke-dasharray:9,5!important;stroke-dashoffset:900;animation:dash 50s linear infinite;stroke-linecap:round;}#mermaid-svg-qYGd4FHsErSHwfKl .edge-animation-fast{stroke-dasharray:9,5!important;stroke-dashoffset:900;animation:dash 20s linear infinite;stroke-linecap:round;}#mermaid-svg-qYGd4FHsErSHwfKl .error-icon{fill:#552222;}#mermaid-svg-qYGd4FHsErSHwfKl .error-text{fill:#552222;stroke:#552222;}#mermaid-svg-qYGd4FHsErSHwfKl .edge-thickness-normal{stroke-width:1px;}#mermaid-svg-qYGd4FHsErSHwfKl .edge-thickness-thick{stroke-width:3.5px;}#mermaid-svg-qYGd4FHsErSHwfKl .edge-pattern-solid{stroke-dasharray:0;}#mermaid-svg-qYGd4FHsErSHwfKl .edge-thickness-invisible{stroke-width:0;fill:none;}#mermaid-svg-qYGd4FHsErSHwfKl .edge-pattern-dashed{stroke-dasharray:3;}#mermaid-svg-qYGd4FHsErSHwfKl .edge-pattern-dotted{stroke-dasharray:2;}#mermaid-svg-qYGd4FHsErSHwfKl .marker{fill:#333333;stroke:#333333;}#mermaid-svg-qYGd4FHsErSHwfKl .marker.cross{stroke:#333333;}#mermaid-svg-qYGd4FHsErSHwfKl svg{font-family:"trebuchet ms",verdana,arial,sans-serif;font-size:16px;}#mermaid-svg-qYGd4FHsErSHwfKl p{margin:0;}#mermaid-svg-qYGd4FHsErSHwfKl .label{font-family:"trebuchet ms",verdana,arial,sans-serif;color:#333;}#mermaid-svg-qYGd4FHsErSHwfKl .cluster-label text{fill:#333;}#mermaid-svg-qYGd4FHsErSHwfKl .cluster-label span{color:#333;}#mermaid-svg-qYGd4FHsErSHwfKl .cluster-label span p{background-color:transparent;}#mermaid-svg-qYGd4FHsErSHwfKl .label text,#mermaid-svg-qYGd4FHsErSHwfKl span{fill:#333;color:#333;}#mermaid-svg-qYGd4FHsErSHwfKl .node rect,#mermaid-svg-qYGd4FHsErSHwfKl .node circle,#mermaid-svg-qYGd4FHsErSHwfKl .node ellipse,#mermaid-svg-qYGd4FHsErSHwfKl .node polygon,#mermaid-svg-qYGd4FHsErSHwfKl .node path{fill:#ECECFF;stroke:#9370DB;stroke-width:1px;}#mermaid-svg-qYGd4FHsErSHwfKl .rough-node .label text,#mermaid-svg-qYGd4FHsErSHwfKl .node .label text,#mermaid-svg-qYGd4FHsErSHwfKl .image-shape .label,#mermaid-svg-qYGd4FHsErSHwfKl .icon-shape .label{text-anchor:middle;}#mermaid-svg-qYGd4FHsErSHwfKl .node .katex path{fill:#000;stroke:#000;stroke-width:1px;}#mermaid-svg-qYGd4FHsErSHwfKl .rough-node .label,#mermaid-svg-qYGd4FHsErSHwfKl .node .label,#mermaid-svg-qYGd4FHsErSHwfKl .image-shape .label,#mermaid-svg-qYGd4FHsErSHwfKl .icon-shape .label{text-align:center;}#mermaid-svg-qYGd4FHsErSHwfKl .node.clickable{cursor:pointer;}#mermaid-svg-qYGd4FHsErSHwfKl .root .anchor path{fill:#333333!important;stroke-width:0;stroke:#333333;}#mermaid-svg-qYGd4FHsErSHwfKl .arrowheadPath{fill:#333333;}#mermaid-svg-qYGd4FHsErSHwfKl .edgePath .path{stroke:#333333;stroke-width:2.0px;}#mermaid-svg-qYGd4FHsErSHwfKl .flowchart-link{stroke:#333333;fill:none;}#mermaid-svg-qYGd4FHsErSHwfKl .edgeLabel{background-color:rgba(232,232,232, 0.8);text-align:center;}#mermaid-svg-qYGd4FHsErSHwfKl .edgeLabel p{background-color:rgba(232,232,232, 0.8);}#mermaid-svg-qYGd4FHsErSHwfKl .edgeLabel rect{opacity:0.5;background-color:rgba(232,232,232, 0.8);fill:rgba(232,232,232, 0.8);}#mermaid-svg-qYGd4FHsErSHwfKl .labelBkg{background-color:rgba(232, 232, 232, 0.5);}#mermaid-svg-qYGd4FHsErSHwfKl .cluster rect{fill:#ffffde;stroke:#aaaa33;stroke-width:1px;}#mermaid-svg-qYGd4FHsErSHwfKl .cluster text{fill:#333;}#mermaid-svg-qYGd4FHsErSHwfKl .cluster span{color:#333;}#mermaid-svg-qYGd4FHsErSHwfKl div.mermaidTooltip{position:absolute;text-align:center;max-width:200px;padding:2px;font-family:"trebuchet ms",verdana,arial,sans-serif;font-size:12px;background:hsl(80, 100%, 96.2745098039%);border:1px solid #aaaa33;border-radius:2px;pointer-events:none;z-index:100;}#mermaid-svg-qYGd4FHsErSHwfKl .flowchartTitleText{text-anchor:middle;font-size:18px;fill:#333;}#mermaid-svg-qYGd4FHsErSHwfKl rect.text{fill:none;stroke-width:0;}#mermaid-svg-qYGd4FHsErSHwfKl .icon-shape,#mermaid-svg-qYGd4FHsErSHwfKl .image-shape{background-color:rgba(232,232,232, 0.8);text-align:center;}#mermaid-svg-qYGd4FHsErSHwfKl .icon-shape p,#mermaid-svg-qYGd4FHsErSHwfKl .image-shape p{background-color:rgba(232,232,232, 0.8);padding:2px;}#mermaid-svg-qYGd4FHsErSHwfKl .icon-shape .label rect,#mermaid-svg-qYGd4FHsErSHwfKl .image-shape .label rect{opacity:0.5;background-color:rgba(232,232,232, 0.8);fill:rgba(232,232,232, 0.8);}#mermaid-svg-qYGd4FHsErSHwfKl .label-icon{display:inline-block;height:1em;overflow:visible;vertical-align:-0.125em;}#mermaid-svg-qYGd4FHsErSHwfKl .node .label-icon path{fill:currentColor;stroke:revert;stroke-width:revert;}#mermaid-svg-qYGd4FHsErSHwfKl :root{--mermaid-font-family:"trebuchet ms",verdana,arial,sans-serif;} 是

编写 XML 配置文件
是否引入 Schema?
声明 xsi 命名空间
指定名称空间 xmlns
用 schemaLocation 关联 .xsd 文件
XML 编写需遵循 .xsd 定义
无约束,可任意定义标签
软件解析 XML 时按约束校验

XML解析

1 ) DOM解析思想

常用的解析思想是 DOM(Document Object Model):将整个 XML 文档一次性加载到内存,形成树形结构,然后逐层获取数据。

核心对象:

  • Document:整个文档对象
  • Element:标签对象
  • Attribute:属性对象
  • Text:标签体文本

解析过程类似"剥玉米":整体 → 根 → 子元素 → 属性/文本。

以如下XML为例:

xml 复制代码
<students>
    <student id="1">
        <name>张三</name>
        <age>23</age>
    </student>
    <student id="2">
        <name>李四</name>
        <age>24</age>
    </student>
</students>

DOM树结构如下(mermaid):
#mermaid-svg-cHvqhSfP6xwVoepf{font-family:"trebuchet ms",verdana,arial,sans-serif;font-size:16px;fill:#333;}@keyframes edge-animation-frame{from{stroke-dashoffset:0;}}@keyframes dash{to{stroke-dashoffset:0;}}#mermaid-svg-cHvqhSfP6xwVoepf .edge-animation-slow{stroke-dasharray:9,5!important;stroke-dashoffset:900;animation:dash 50s linear infinite;stroke-linecap:round;}#mermaid-svg-cHvqhSfP6xwVoepf .edge-animation-fast{stroke-dasharray:9,5!important;stroke-dashoffset:900;animation:dash 20s linear infinite;stroke-linecap:round;}#mermaid-svg-cHvqhSfP6xwVoepf .error-icon{fill:#552222;}#mermaid-svg-cHvqhSfP6xwVoepf .error-text{fill:#552222;stroke:#552222;}#mermaid-svg-cHvqhSfP6xwVoepf .edge-thickness-normal{stroke-width:1px;}#mermaid-svg-cHvqhSfP6xwVoepf .edge-thickness-thick{stroke-width:3.5px;}#mermaid-svg-cHvqhSfP6xwVoepf .edge-pattern-solid{stroke-dasharray:0;}#mermaid-svg-cHvqhSfP6xwVoepf .edge-thickness-invisible{stroke-width:0;fill:none;}#mermaid-svg-cHvqhSfP6xwVoepf .edge-pattern-dashed{stroke-dasharray:3;}#mermaid-svg-cHvqhSfP6xwVoepf .edge-pattern-dotted{stroke-dasharray:2;}#mermaid-svg-cHvqhSfP6xwVoepf .marker{fill:#333333;stroke:#333333;}#mermaid-svg-cHvqhSfP6xwVoepf .marker.cross{stroke:#333333;}#mermaid-svg-cHvqhSfP6xwVoepf svg{font-family:"trebuchet ms",verdana,arial,sans-serif;font-size:16px;}#mermaid-svg-cHvqhSfP6xwVoepf p{margin:0;}#mermaid-svg-cHvqhSfP6xwVoepf .label{font-family:"trebuchet ms",verdana,arial,sans-serif;color:#333;}#mermaid-svg-cHvqhSfP6xwVoepf .cluster-label text{fill:#333;}#mermaid-svg-cHvqhSfP6xwVoepf .cluster-label span{color:#333;}#mermaid-svg-cHvqhSfP6xwVoepf .cluster-label span p{background-color:transparent;}#mermaid-svg-cHvqhSfP6xwVoepf .label text,#mermaid-svg-cHvqhSfP6xwVoepf span{fill:#333;color:#333;}#mermaid-svg-cHvqhSfP6xwVoepf .node rect,#mermaid-svg-cHvqhSfP6xwVoepf .node circle,#mermaid-svg-cHvqhSfP6xwVoepf .node ellipse,#mermaid-svg-cHvqhSfP6xwVoepf .node polygon,#mermaid-svg-cHvqhSfP6xwVoepf .node path{fill:#ECECFF;stroke:#9370DB;stroke-width:1px;}#mermaid-svg-cHvqhSfP6xwVoepf .rough-node .label text,#mermaid-svg-cHvqhSfP6xwVoepf .node .label text,#mermaid-svg-cHvqhSfP6xwVoepf .image-shape .label,#mermaid-svg-cHvqhSfP6xwVoepf .icon-shape .label{text-anchor:middle;}#mermaid-svg-cHvqhSfP6xwVoepf .node .katex path{fill:#000;stroke:#000;stroke-width:1px;}#mermaid-svg-cHvqhSfP6xwVoepf .rough-node .label,#mermaid-svg-cHvqhSfP6xwVoepf .node .label,#mermaid-svg-cHvqhSfP6xwVoepf .image-shape .label,#mermaid-svg-cHvqhSfP6xwVoepf .icon-shape .label{text-align:center;}#mermaid-svg-cHvqhSfP6xwVoepf .node.clickable{cursor:pointer;}#mermaid-svg-cHvqhSfP6xwVoepf .root .anchor path{fill:#333333!important;stroke-width:0;stroke:#333333;}#mermaid-svg-cHvqhSfP6xwVoepf .arrowheadPath{fill:#333333;}#mermaid-svg-cHvqhSfP6xwVoepf .edgePath .path{stroke:#333333;stroke-width:2.0px;}#mermaid-svg-cHvqhSfP6xwVoepf .flowchart-link{stroke:#333333;fill:none;}#mermaid-svg-cHvqhSfP6xwVoepf .edgeLabel{background-color:rgba(232,232,232, 0.8);text-align:center;}#mermaid-svg-cHvqhSfP6xwVoepf .edgeLabel p{background-color:rgba(232,232,232, 0.8);}#mermaid-svg-cHvqhSfP6xwVoepf .edgeLabel rect{opacity:0.5;background-color:rgba(232,232,232, 0.8);fill:rgba(232,232,232, 0.8);}#mermaid-svg-cHvqhSfP6xwVoepf .labelBkg{background-color:rgba(232, 232, 232, 0.5);}#mermaid-svg-cHvqhSfP6xwVoepf .cluster rect{fill:#ffffde;stroke:#aaaa33;stroke-width:1px;}#mermaid-svg-cHvqhSfP6xwVoepf .cluster text{fill:#333;}#mermaid-svg-cHvqhSfP6xwVoepf .cluster span{color:#333;}#mermaid-svg-cHvqhSfP6xwVoepf div.mermaidTooltip{position:absolute;text-align:center;max-width:200px;padding:2px;font-family:"trebuchet ms",verdana,arial,sans-serif;font-size:12px;background:hsl(80, 100%, 96.2745098039%);border:1px solid #aaaa33;border-radius:2px;pointer-events:none;z-index:100;}#mermaid-svg-cHvqhSfP6xwVoepf .flowchartTitleText{text-anchor:middle;font-size:18px;fill:#333;}#mermaid-svg-cHvqhSfP6xwVoepf rect.text{fill:none;stroke-width:0;}#mermaid-svg-cHvqhSfP6xwVoepf .icon-shape,#mermaid-svg-cHvqhSfP6xwVoepf .image-shape{background-color:rgba(232,232,232, 0.8);text-align:center;}#mermaid-svg-cHvqhSfP6xwVoepf .icon-shape p,#mermaid-svg-cHvqhSfP6xwVoepf .image-shape p{background-color:rgba(232,232,232, 0.8);padding:2px;}#mermaid-svg-cHvqhSfP6xwVoepf .icon-shape .label rect,#mermaid-svg-cHvqhSfP6xwVoepf .image-shape .label rect{opacity:0.5;background-color:rgba(232,232,232, 0.8);fill:rgba(232,232,232, 0.8);}#mermaid-svg-cHvqhSfP6xwVoepf .label-icon{display:inline-block;height:1em;overflow:visible;vertical-align:-0.125em;}#mermaid-svg-cHvqhSfP6xwVoepf .node .label-icon path{fill:currentColor;stroke:revert;stroke-width:revert;}#mermaid-svg-cHvqhSfP6xwVoepf :root{--mermaid-font-family:"trebuchet ms",verdana,arial,sans-serif;} Document
根Element: students
Element: student
Element: student
Attribute: id=1
Element: name
Element: age
Text: 张三
Text: 23
Attribute: id=2
Element: name
Element: age
Text: 李四
Text: 24

2 ) dom4j解析实战

2.1 准备工作

dom4j 是一个第三方开源的 XML 解析框架,使用前需下载并导入 dom4j-1.6.1.jar

项目目录结构(放置 jar 包):

dir 复制代码
myxml/
├── libs/
│   └── dom4j-1.6.1.jar 
├── xml/
│   └── student.xml 
└── src/
    └── com/wb/xmlparse/
        ├── Student.java 
        └── XmlParse.java 

将 jar 包添加为库:右键 jar → Add as Library。

2.2 解析代码

需求:解析 student.xml,将数据封装为 Student 对象,存入 ArrayList 并打印

实体类 Student.java:

java 复制代码
package com.wb.xmlparse;
 
public class Student {
    private String id;
    private String name;
    private int age;
 
    public Student() {}
 
    public Student(String id, String name, int age) {
        this.id = id;
        this.name = name;
        this.age = age;
    }
 
    // getter & setter & toString 省略...
}

解析类 XmlParse.java:

java 复制代码
package com.wb.xmlparse;
 
import org.dom4j.Attribute;
import org.dom4j.Document;
import org.dom4j.DocumentException;
import org.dom4j.Element;
import org.dom4j.io.SAXReader;
 
import java.io.File;
import java.util.ArrayList;
import java.util.List;
 
/*
利用dom4j解析xml文件 
 */
public class XmlParse {
    public static void main(String[] args) throws DocumentException {
        //1. 创建解析器对象 
        SAXReader saxReader = new SAXReader();
        //2. 将xml文件加载到内存,获取Document文档对象(整体)
        Document document = saxReader.read(new File("myxml\\xml\\student.xml"));
        //3. 获取根标签 students 
        Element rootElement = document.getRootElement();
        //4. 获取所有指定的子标签 student (避免获取到其他标签如aaa)
        List<Element> studentElements = rootElement.elements("student");
 
        //准备集合存储学生对象 
        ArrayList<Student> list = new ArrayList<>();
 
        //5. 遍历每个student标签 
        for (Element element : studentElements) {
            // 获取id属性值 
            Attribute attribute = element.attribute("id");
            String id = attribute.getValue();
 
            // 获取name子标签,再获取其文本内容 
            Element nameElement = element.element("name");
            String name = nameElement.getText();
 
            // 获取age子标签,再获取其文本内容 
            Element ageElement = element.element("age");
            String ageStr = ageElement.getText();
            // 转为int 
            int age = Integer.parseInt(ageStr);
 
            // 封装到Student对象 
            Student s = new Student(id, name, age);
            list.add(s);
        }
 
        // 遍历集合输出 
        for (Student student : list) {
            System.out.println(student);
        }
    }
}

关键方法总结:

  • SAXReader.read(file):读取 XML,返回 Document
  • document.getRootElement():获取根元素
  • rootElement.elements("子标签名"):获取所有指定名称的子元素集合
  • element.attribute("属性名"):获取属性对象,再 .getValue() 得到属性值
  • element.element("子标签名"):获取单个指定子元素
  • element.getText():获取元素中的文本内容

解析流程图:
#mermaid-svg-60ApR1T7ZLXr6cJc{font-family:"trebuchet ms",verdana,arial,sans-serif;font-size:16px;fill:#333;}@keyframes edge-animation-frame{from{stroke-dashoffset:0;}}@keyframes dash{to{stroke-dashoffset:0;}}#mermaid-svg-60ApR1T7ZLXr6cJc .edge-animation-slow{stroke-dasharray:9,5!important;stroke-dashoffset:900;animation:dash 50s linear infinite;stroke-linecap:round;}#mermaid-svg-60ApR1T7ZLXr6cJc .edge-animation-fast{stroke-dasharray:9,5!important;stroke-dashoffset:900;animation:dash 20s linear infinite;stroke-linecap:round;}#mermaid-svg-60ApR1T7ZLXr6cJc .error-icon{fill:#552222;}#mermaid-svg-60ApR1T7ZLXr6cJc .error-text{fill:#552222;stroke:#552222;}#mermaid-svg-60ApR1T7ZLXr6cJc .edge-thickness-normal{stroke-width:1px;}#mermaid-svg-60ApR1T7ZLXr6cJc .edge-thickness-thick{stroke-width:3.5px;}#mermaid-svg-60ApR1T7ZLXr6cJc .edge-pattern-solid{stroke-dasharray:0;}#mermaid-svg-60ApR1T7ZLXr6cJc .edge-thickness-invisible{stroke-width:0;fill:none;}#mermaid-svg-60ApR1T7ZLXr6cJc .edge-pattern-dashed{stroke-dasharray:3;}#mermaid-svg-60ApR1T7ZLXr6cJc .edge-pattern-dotted{stroke-dasharray:2;}#mermaid-svg-60ApR1T7ZLXr6cJc .marker{fill:#333333;stroke:#333333;}#mermaid-svg-60ApR1T7ZLXr6cJc .marker.cross{stroke:#333333;}#mermaid-svg-60ApR1T7ZLXr6cJc svg{font-family:"trebuchet ms",verdana,arial,sans-serif;font-size:16px;}#mermaid-svg-60ApR1T7ZLXr6cJc p{margin:0;}#mermaid-svg-60ApR1T7ZLXr6cJc .label{font-family:"trebuchet ms",verdana,arial,sans-serif;color:#333;}#mermaid-svg-60ApR1T7ZLXr6cJc .cluster-label text{fill:#333;}#mermaid-svg-60ApR1T7ZLXr6cJc .cluster-label span{color:#333;}#mermaid-svg-60ApR1T7ZLXr6cJc .cluster-label span p{background-color:transparent;}#mermaid-svg-60ApR1T7ZLXr6cJc .label text,#mermaid-svg-60ApR1T7ZLXr6cJc span{fill:#333;color:#333;}#mermaid-svg-60ApR1T7ZLXr6cJc .node rect,#mermaid-svg-60ApR1T7ZLXr6cJc .node circle,#mermaid-svg-60ApR1T7ZLXr6cJc .node ellipse,#mermaid-svg-60ApR1T7ZLXr6cJc .node polygon,#mermaid-svg-60ApR1T7ZLXr6cJc .node path{fill:#ECECFF;stroke:#9370DB;stroke-width:1px;}#mermaid-svg-60ApR1T7ZLXr6cJc .rough-node .label text,#mermaid-svg-60ApR1T7ZLXr6cJc .node .label text,#mermaid-svg-60ApR1T7ZLXr6cJc .image-shape .label,#mermaid-svg-60ApR1T7ZLXr6cJc .icon-shape .label{text-anchor:middle;}#mermaid-svg-60ApR1T7ZLXr6cJc .node .katex path{fill:#000;stroke:#000;stroke-width:1px;}#mermaid-svg-60ApR1T7ZLXr6cJc .rough-node .label,#mermaid-svg-60ApR1T7ZLXr6cJc .node .label,#mermaid-svg-60ApR1T7ZLXr6cJc .image-shape .label,#mermaid-svg-60ApR1T7ZLXr6cJc .icon-shape .label{text-align:center;}#mermaid-svg-60ApR1T7ZLXr6cJc .node.clickable{cursor:pointer;}#mermaid-svg-60ApR1T7ZLXr6cJc .root .anchor path{fill:#333333!important;stroke-width:0;stroke:#333333;}#mermaid-svg-60ApR1T7ZLXr6cJc .arrowheadPath{fill:#333333;}#mermaid-svg-60ApR1T7ZLXr6cJc .edgePath .path{stroke:#333333;stroke-width:2.0px;}#mermaid-svg-60ApR1T7ZLXr6cJc .flowchart-link{stroke:#333333;fill:none;}#mermaid-svg-60ApR1T7ZLXr6cJc .edgeLabel{background-color:rgba(232,232,232, 0.8);text-align:center;}#mermaid-svg-60ApR1T7ZLXr6cJc .edgeLabel p{background-color:rgba(232,232,232, 0.8);}#mermaid-svg-60ApR1T7ZLXr6cJc .edgeLabel rect{opacity:0.5;background-color:rgba(232,232,232, 0.8);fill:rgba(232,232,232, 0.8);}#mermaid-svg-60ApR1T7ZLXr6cJc .labelBkg{background-color:rgba(232, 232, 232, 0.5);}#mermaid-svg-60ApR1T7ZLXr6cJc .cluster rect{fill:#ffffde;stroke:#aaaa33;stroke-width:1px;}#mermaid-svg-60ApR1T7ZLXr6cJc .cluster text{fill:#333;}#mermaid-svg-60ApR1T7ZLXr6cJc .cluster span{color:#333;}#mermaid-svg-60ApR1T7ZLXr6cJc div.mermaidTooltip{position:absolute;text-align:center;max-width:200px;padding:2px;font-family:"trebuchet ms",verdana,arial,sans-serif;font-size:12px;background:hsl(80, 100%, 96.2745098039%);border:1px solid #aaaa33;border-radius:2px;pointer-events:none;z-index:100;}#mermaid-svg-60ApR1T7ZLXr6cJc .flowchartTitleText{text-anchor:middle;font-size:18px;fill:#333;}#mermaid-svg-60ApR1T7ZLXr6cJc rect.text{fill:none;stroke-width:0;}#mermaid-svg-60ApR1T7ZLXr6cJc .icon-shape,#mermaid-svg-60ApR1T7ZLXr6cJc .image-shape{background-color:rgba(232,232,232, 0.8);text-align:center;}#mermaid-svg-60ApR1T7ZLXr6cJc .icon-shape p,#mermaid-svg-60ApR1T7ZLXr6cJc .image-shape p{background-color:rgba(232,232,232, 0.8);padding:2px;}#mermaid-svg-60ApR1T7ZLXr6cJc .icon-shape .label rect,#mermaid-svg-60ApR1T7ZLXr6cJc .image-shape .label rect{opacity:0.5;background-color:rgba(232,232,232, 0.8);fill:rgba(232,232,232, 0.8);}#mermaid-svg-60ApR1T7ZLXr6cJc .label-icon{display:inline-block;height:1em;overflow:visible;vertical-align:-0.125em;}#mermaid-svg-60ApR1T7ZLXr6cJc .node .label-icon path{fill:currentColor;stroke:revert;stroke-width:revert;}#mermaid-svg-60ApR1T7ZLXr6cJc :root{--mermaid-font-family:"trebuchet ms",verdana,arial,sans-serif;} 创建SAXReader
读取XML获得Document
获取根元素 Element
获取指定子元素列表
遍历每个子元素
获取属性: attribute.getValue
获取子元素: element.element...getText
封装为对象
加入集合
遍历输出

这样我们就完成了 XML 的解析。

总结

通过本文,我们从 XML 的基础语法开始,学习了 DTD 和 Schema 两种约束技术,并通过 dom4j 实现了 XML 文件的解析,掌握了 Java 中处理 XML 的核心技能。