XML 的语法核心是六条硬规则:单一根元素、标签闭合、嵌套不交叉、大小写敏感、属性值必须加引号、特殊字符必须转义。违反任何一条,解析器直接拒绝整份文档——没有"尽力显示"这回事。承接 1.1 节解剖过的书店文档,本节把每一刀的标准切法与错误切法对照讲透。
第一刀,根元素唯一。第二刀,标签必须闭合。第三刀,嵌套不能交叉。这三条决定"树"能否成立。第四刀,大小写敏感。第五刀,属性值加引号。第六刀,特殊字符转义。逐条上手术台。
闭合与交叉。看一个经典错误:
<!-- 错误:标签交叉嵌套,解析器报错 --> <p><b>库存不足,请尽快补货</p></b> <!-- 正确:后开的标签必须先关 --> <p><b>库存不足,请尽快补货</b></p> <!-- 无内容的元素可以用自闭合简写 --> <restock/> <!-- 等价于 <restock></restock> -->
解析器读到 </p> 时会发现 b 还开着——交叉意味着"谁是父谁是子"无法判定,树就断了。浏览器渲染 HTML 时会宽容地猜,XML 解析器不会,这是两者工程态度的根本差异。
大小写敏感。<Stock> 与 <stock> 是两个不同标签:
<book> <Stock>42</Stock> <!-- 定义时用小写 stock --> </book> <!-- 结果:解析器报错 stock 未闭合,或查询 stock 时取不到值 -->
从 HTML 转过来的读者最容易栽在这里,因为 HTML 里 <P> 和 <p> 等价。工程约定上,XML 元素名统一用小写是更稳的习惯。
引号与转义。属性值必须用单引号或双引号括起,不能裸奔。而内容里出现尖括号、与符号时必须转义,否则会被误认成标签:
<!-- 错误:裸用 < 与 & --> <query>price < 100 & stock > 0</query> <!-- 正确:五个预定义实体 --> <query>price < 100 & stock > 0</query> <!-- 实体对照:< 小于号 > 大于号 & 与符号 ' 单引号 " 双引号 -->
转义不是可有可无的装饰。上面那段错误写法里,< 100 的 < 后面跟空格,解析器虽大概率报错,但某些宽松工具的行为不可预期——契约语言里不要赌运气。
💡 一个直觉:把 XML 当法律文本读,每个字符都有含义,没有"大概行"。
空白会被保留。<title>算法导论</title> 和 <title> 算法导论 </title> 是不同内容——XML 不修剪元素内的空白。做数据比对时这是隐形炸弹,收方常需自行 trim。而标签之间的缩进空白属于标记间空白,一般可被解析器忽略。
元素命名规则:字母或下划线开头,可含数字、连字符、点号;不能以 xml(任何大小写组合)开头;不能含空格。合法与非法对照:
<book-title/> <!-- 合法:连字符 --> <book.title/> <!-- 合法:点号,但易与属性混淆,不推荐 --> <book_2/> <!-- 合法:下划线开头也行 --> <2book/> <!-- 非法:数字开头 --> <book title/> <!-- 非法:含空格 --> <xmlRecord/> <!-- 非法:xml 前缀被保留 -->
把常见错误集中到一份文档里做会诊,读者可先自己找错再对照:
<?xml version="1.0" encoding="UTF-8"?> <shipment> <Order id=1001> <item>螺栓 & 垫片</item> <Qty>200<Qty> </Order> <order>补发单</order> </shipment>
四处病灶:id=1001 属性值没加引号;& 没转义;<Qty>200<Qty> 结束标签少了斜杠;<Order> 与 <order> 是两个元素(大小写敏感,此处恰好不是语法错误而是语义隐患——同一个业务概念写了两种标签)。用任何校验器跑一遍,前三处会直接报错,行号与列号都会给出。这个会诊案例值得动手重打一遍:改到校验器通过的那一刻,六条规则就长在手上了。
规则背得再熟,不如让解析器亲手判一次。用浏览器或任意校验工具(第 7 章系统盘点)打开上面那份"全错"文档,观察输出:多数工具会停在第一个错误处,报出元素名、行列位置;改掉这处再跑,暴露下一处。逐个修复的过程就是六条规则从纸面进入手指的过程。
这里有个值得体会的细节:解析器的报错顺序往往与错误在文档中的出现顺序一致,但报错位置与你的直觉位置可能差很远——交叉嵌套的错误常在几行之后才被发现。因此养成一个习惯:修完一处立刻重跑,不要凭一次报错连改三处,否则新的报错会与旧报错混在一起,越改越乱。小步提交、逐步验证,这条软件工程的基本功在 XML 排错上体现得最直观。
练习建议:把本节所有"错误示例"各抄一份单独存文件,逐一跑校验,记下每种错误对应的报错关键词。这张"错误-报错对照表"在日后处理他人文档时就是你的速查手册——看到报错关键词就能反推病灶类型,配合 3.1 节的报错解读训练,排错效率会有质的提升。
最后说一个心态问题。初学者常在连续报错后怀疑"XML 是不是特别难",其实恰恰相反:XML 规则少而明确,报错诚实而具体,属于"错得坦荡"的格式。真正让人头疼的是那些不报错、静默猜出意外结果的宽容工具。把每次报错当一次免费的教学,改完记住关键词,六条规则两三天就能长进肌肉记忆。
<x/> 适合空元素;到这里,解剖台上的文档已经"看起来规范"。但结构细节——声明里还能写什么、属性与子元素怎么取舍——需要更细的刀法,进入第 2 章。