XML(Extensible Markup Language,可扩展标记语言)是由万维网联盟(W3C)于1998年2月发布的一种标记语言,其核心设计目标是传输和存储数据,而非直接用于显示数据(这一点与HTML有本质区别)。
XML的“可扩展性”体现在:它没有预定义标签,用户可以根据需求自定义标签,只要遵循语法规则即可。这种灵活性使其成为跨平台、跨系统数据交换的重要标准,广泛应用于配置文件、数据传输、文档存储等场景。
从历史背景看,XML源于SGML(标准通用标记语言)——SGML功能强大但过于复杂,难以在互联网普及。XML简化了SGML的语法,保留了其结构化数据的核心能力,同时降低了使用门槛,成为互联网时代数据交换的早期标杆。
XML文档的结构严谨,必须遵循一套严格的语法规范,否则会被视为“无效XML”,无法被解析器正确处理。
XML文档采用“树状结构”,所有内容被包裹在一个根元素中,根元素是整个文档的唯一顶层节点,其他元素都是其子孙节点。例如:
<bookstore>
<book category=" fiction ">
<title> The Great Gatsby title>
<author> F. Scott Fitzgerald author>
<price> 15.99 price>
book>
<book category=" non-fiction ">
<title> Sapiens title>
<author> Yuval Noah Harari author>
<price> 22.50 price>
book>
bookstore>
是唯一的顶层元素,包含所有其他内容。
是
的子元素,
、
等是
的子元素,形成清晰的父子关系。XML语法严格,任何违反规则的文档都会被解析器拒绝,这是其与HTML(语法松散,标签可不闭合)的核心区别。
标签必须闭合:所有元素必须有开始标签和结束标签,例如
对应 。空元素(无内容)可简写为
(等价于
)。
❌ 错误:
(缺少结束标签)
✅ 正确:
或
(空元素)
标签必须正确嵌套:子元素必须完全包含在父元素内,不能交叉嵌套。
❌ 错误:
(交叉嵌套)
✅ 正确:
属性值必须加引号:元素的属性值必须用单引号(')或双引号(")包裹,且前后一致。
❌ 错误:
(属性值无引号)
✅ 正确:
或
大小写敏感:XML标签区分大小写,
和
是两个不同的元素。
❌ 错误:
(开始与结束标签大小写不一致)
✅ 正确:
或
特殊字符处理:XML中,<
、>
、&
、"
、'
是保留字符,直接使用会导致解析错误,需用实体引用或CDATA块处理:
<
(<)、>
(>)、&
(&)、"
(")、'
(')。He said "Hello"
表示 He said "Hello"
。
包裹,内部内容会被解析器视为纯文本,无需转义。 d) { ... } ]]>
XML中,数据可以通过“子元素”或“属性”存储,两者的使用场景需明确区分:
子元素:适合存储核心数据,结构灵活,可嵌套其他元素。
例:
属性:适合存储“元数据”(描述元素的附加信息),结构简单,不可嵌套。
例:
(category是描述book的附加信息)
最佳实践:避免过度使用属性。属性难以存储复杂结构,且在解析时不如子元素直观(例如,属性值无法包含多行文本,而子元素可以)。
XML对元素、属性的命名有明确规范,同时支持注释以增强文档可读性。
<1book>
无效)。
无效,可用
或
)。xml
(或XML、Xml等大小写变体)开头,因为这些前缀被W3C保留用于标准功能(如命名空间)。
和
是两个不同的元素。XML注释的格式为 ,需注意:
注释 -->
无效)。
)之前。 category="fiction">
无效)。例:
<bookstore>
<book category="fiction">
<title>The Great Gatsbytitle>
<author>F. Scott Fitzgeraldauthor>
book>
bookstore>
当不同来源的XML文档合并时,可能出现“同名元素但含义不同”的冲突(例如,两个文档都有
元素,一个表示书名,一个表示网页标题)。命名空间通过唯一标识区分这些元素。
命名空间通过一个统一资源标识符(Uniform Resource Identifier,URI) 来标识,通常是一个URL(如 https://example.com/books
),但URL本身无需可访问,仅作为唯一标识。
命名空间通过 xmlns
属性声明,有两种形式:
声明默认命名空间后,该范围内的所有元素默认属于此命名空间,无需前缀。
格式:xmlns="URI"
例:
<bookstore xmlns="https://example.com/books">
<book>
<title>The Great Gatsbytitle>
book>
bookstore>
当需要同时使用多个命名空间时,用前缀区分,格式:xmlns:前缀="URI"
。引用时需在元素前加“前缀:”。
例:一个文档同时包含“书店”和“图书馆”的元素,两者都有
:
<root
xmlns:book="https://example.com/books"
xmlns:lib="https://example.com/library"
>
<book:title>The Great Gatsbybook:title>
<lib:title>New York Public Librarylib:title>
root>
命名空间的声明只在当前元素及其子元素中有效(除非被子元素重新声明覆盖)。
例:
<bookstore xmlns="https://example.com/books">
<book>
<title>1984title>
book>
<magazine xmlns="https://example.com/magazines">
<title>Timetitle>
magazine>
bookstore>
为确保XML文档的结构符合预期(例如,
必须包含
和
),需要使用“约束语言”定义规则。常见的约束方式有DTD和XML Schema(XSD)。
DTD是最早的XML约束规范,语法简单,但功能有限,不支持数据类型。
内部DTD:约束规则嵌入XML文档中,用 声明。
例:
DOCTYPE bookstore [
<!ELEMENT bookstore (book+)>
<!ELEMENT book (title, author, price)>
<!ELEMENT title (#PCDATA)>
<!ELEMENT author (#PCDATA)>
<!ELEMENT price (#PCDATA)>
<!ATTLIST book category CDATA #REQUIRED>
]>
<bookstore>
<book category="fiction">
<title>The Great Gatsbytitle>
<author>F. Scott Fitzgeraldauthor>
<price>15.99price>
book>
bookstore>
外部DTD:约束规则存储在外部文件中,XML文档通过文件名引用,适合多个文档共享约束。
例:
DOCTYPE bookstore SYSTEM "bookstore.dtd">
<bookstore>
bookstore>
元素声明:
内容模型可包含:
#PCDATA
:表示元素包含文本数据(Parsed Character Data)。(title, author)
表示元素必须包含title和author,顺序固定。+
(1次或多次)、*
(0次或多次)、?
(0次或1次)、|
(或,如 (title | name)
表示二选一)。属性声明:
类型:CDATA
(文本)、ID
(唯一标识)、IDREF
(引用其他ID)、ENUM
(枚举值,如 (fiction|non-fiction)
)等。
默认值:#REQUIRED
(必须出现)、#IMPLIED
(可选)、#FIXED "值"
(固定值)、具体默认值(如 category "fiction"
)。
实体声明:,用于定义可重用的文本片段(类似变量)。
例:
DOCTYPE bookstore [
<!ENTITY publisher "Scribner">
]>
<bookstore>
<book>
<publisher>&publisher;publisher>
book>
bookstore>
必须是数字,只能限定为文本。
)可能导致XXE(XML外部实体注入)攻击,泄露服务器敏感文件。XML Schema(简称XSD)是W3C推荐的新一代约束语言,基于XML语法,功能更强大,解决了DTD的诸多缺陷。
必须是 decimal
类型)。一个XSD文档本身也是XML文档,根元素通常是
,并通过命名空间 http://www.w3.org/2001/XMLSchema
标识。
例:为书店文档定义XSD约束(bookstore.xsd
):
<xsd:schema xmlns:xsd="http://www.w3.org/2001/XMLSchema"
targetNamespace="https://example.com/books"
<xsd:element name="bookstore">
<xsd:complexType>
<xsd:sequence>
<xsd:element name="book" maxOccurs="unbounded">
<xsd:complexType>
<xsd:sequence>
<xsd:element name="title" type="xsd:string"/>
<xsd:element name="author" type="xsd:string"/>
<xsd:element name="price">
<xsd:simpleType>
<xsd:restriction base="xsd:decimal">
<xsd:minExclusive value="0"/>
xsd:restriction>
xsd:simpleType>
xsd:element>
xsd:sequence>
<xsd:attribute name="category" use="required">
<xsd:simpleType>
<xsd:restriction base="xsd:string">
<xsd:enumeration value="fiction"/>
<xsd:enumeration value="non-fiction"/>
xsd:restriction>
xsd:simpleType>
xsd:attribute>
xsd:complexType>
xsd:element>
xsd:sequence>
xsd:complexType>
xsd:element>
xsd:schema>
XML文档通过 xsi:schemaLocation
属性引用XSD,格式为 命名空间 URI XSD文件路径
。
例:
<bookstore
xmlns="https://example.com/books"
>
<book category="fiction">
<title>The Great Gatsbytitle>
<author>F. Scott Fitzgeraldauthor>
<price>15.99price>
book>
bookstore>
解析是XML处理的核心步骤,即读取XML文档并将其转换为程序可操作的数据结构。常见的解析方式有DOM、SAX和StAX。
DOM将整个XML文档加载到内存中,构建一个树状结构(文档树),每个节点(元素、属性、文本等)都是树的一部分。
的值、删除某个
元素),适合需要频繁修改文档的场景。例(Java DOM解析示例):
import javax.xml.parsers.DocumentBuilderFactory;
import org.w3c.dom.Document;
import org.w3c.dom.NodeList;
public class DOMExample {
public static void main(String[] args) throws Exception {
// 加载XML文档到内存,构建Document对象
Document doc = DocumentBuilderFactory.newInstance()
.newDocumentBuilder()
.parse("bookstore.xml");
// 获取所有book元素
NodeList books = doc.getElementsByTagName("book");
// 遍历book元素,打印title
for (int i = 0; i < books.getLength(); i++) {
String title = books.item(i).getChildNodes().item(1).getTextContent();
System.out.println(title);
}
}
}
SAX是事件驱动的解析方式,逐行读取XML文档,当遇到标签、文本等内容时触发相应事件(如 startElement
、endElement
、characters
),程序通过监听事件处理数据。
例(Java SAX解析示例):
import javax.xml.parsers.SAXParserFactory;
import org.xml.sax.helpers.DefaultHandler;
import org.xml.sax.Attributes;
public class SAXExample extends DefaultHandler {
private boolean isTitle = false;
// 遇到开始标签时触发
@Override
public void startElement(String uri, String localName, String qName, Attributes attributes) {
if (qName.equals("title")) {
isTitle = true;
}
}
// 遇到文本内容时触发
@Override
public void characters(char[] ch, int start, int length) {
if (isTitle) {
System.out.println(new String(ch, start, length)); // 打印title内容
isTitle = false;
}
}
public static void main(String[] args) throws Exception {
SAXParserFactory.newInstance().newSAXParser()
.parse("bookstore.xml", new SAXExample());
}
}
StAX是介于DOM和SAX之间的解析方式,允许程序主动“拉取”事件(而非被动等待事件触发),兼具SAX的低内存占用和DOM的灵活性。
尽管JSON在轻量级数据交换中逐渐替代XML,但XML凭借其严格的结构和强大的约束能力,仍在诸多领域发挥重要作用。
...
),相比JSON("title": "..."
)更占用空间。特性 | XML | JSON | HTML |
---|---|---|---|
设计目标 | 传输/存储数据,强调结构约束 | 轻量级数据交换,简洁高效 | 显示数据,定义网页结构 |
标签 | 自定义,需闭合,大小写敏感 | 无标签,用键值对,大小写敏感 | 预定义标签,部分可省略闭合 |
约束能力 | 支持DTD、XSD严格约束 | 无内置约束(需额外工具) | 无约束(依赖浏览器容错) |
扩展性 | 强(命名空间解决冲突) | 弱(无内置冲突解决机制) | 弱(标签固定) |
适用场景 | 复杂结构、需严格验证的场景 | 轻量级API数据交换 | 网页展示 |
XML是一种功能强大的可扩展标记语言,以严格的语法、结构化的树状模型和强大的约束机制(DTD、XSD)为核心,广泛应用于配置文件、数据交换、文档存储等场景。尽管JSON在轻量级场景中更受欢迎,但XML在需要复杂结构和严格验证的领域(如企业级系统、文档标准)仍不可替代。 掌握XML的语法规则、命名空间、约束机制及解析方式,对于理解现有系统(如Spring配置、Office文档)和设计跨平台数据交换方案至关重要。