XInclude 是 W3C 标准定义的 XML 内容内联包含机制,需显式声明命名空间并由支持处理器展开,工作在信息项层面,保留命名空间、属性等结构,支持 parse="xml"/"text" 和 fallback 错误处理。

什么是 XInclude?它和普通 XML 包含有什么区别
XInclude 是 W3C 标准定义的一种机制,用于在 XML 文档中“引用并内联插入”其他 XML 文档的内容。它不是 XML 解析器默认启用的功能,而是需要显式声明命名空间并由支持 XInclude 的处理器(如 libxml2、lxml、Java Transformer 或 xmllint --xinclude)主动展开。
它和简单的文本包含(比如预处理器 #include)或 DTD 实体不同:XInclude 工作在解析后的信息项层面,能保留被包含文档的命名空间、属性、注释等结构信息,且支持错误处理策略(fallback)。
如何在 XML 中写一个基本的 XInclude 引用
必须满足三个前提:声明 XInclude 命名空间、使用 xi:include 元素、确保处理器启用 XInclude 支持。常见错误是只写了标签却没声明命名空间,导致解析失败或静默忽略。
-
xmlns:xi="http://www.w3.org/2001/XInclude"必须出现在根元素或xi:include父元素上 -
href属性值是相对或绝对 URI,不支持本地文件路径裸写(如config.xml可以,C:\data\config.xml在多数实现中会失败) - 被包含文件必须是格式良好的 XML,不能是 HTML 或片段(除非用
parse="text")
<?xml version="1.0"?><root xmlns:xi="http://www.w3.org/2001/XInclude"><include href="header.xml"></include>Main content <include href="footer.xml"></include></root>
parse="text" 和 parse="xml" 的实际影响
parse 属性决定如何解释被包含资源的内容类型,直接影响解析行为和错误边界:
分析 Java Spring Boot 后端 Controller 代码,自动生成 Markdown 格式的接口文档。当用户说“生成 Java 接口文档”、“生成 API 文档”、“从 Spring 代码生成文档”时触发。
-
parse="xml"(默认):要求目标文件是良构 XML,整个内容作为子树插入;若出错,按xi:fallback处理或报错 -
parse="text":把目标文件当纯文本读入,自动转义特殊字符(→),适合包含 README、SQL 片段、配置注释等非 XML 内容 - 不支持
parse="html"—— 即使目标是 HTML,也需先转为 XHTML 或用parse="text"
<include href="notes.txt" parse="text"></include><include href="menu.xml" parse="xml"></include>
为什么 XInclude 在 Python lxml 中默认不生效
lxml.etree.parse() 默认禁用 XInclude,必须显式调用 etree.XInclude() 或使用 parser=etree.XMLParser(load_dtd=True, xinclude=True)(注意:后者仅对部分版本有效)。最可靠的方式是解析后手动展开:
from lxml import etree
<p>doc = etree.parse("main.xml")
xinclude = etree.XInclude()
xinclude(doc) # 就地修改 doc 树
print(etree.tostring(doc, encoding="unicode"))</p>
容易踩的坑包括:忘记调用 xinclude(doc)、在调用前对 doc 做了不可逆操作(如 doc.xinclude() 方法不存在)、或误以为 etree.parse(..., resolve_entities=True) 会处理 XInclude(它只处理 DTD 实体)。
嵌套 XInclude(A 包含 B,B 包含 C)是合法的,但所有层级都依赖处理器是否递归展开 —— lxml 的 XInclude() 默认支持,而某些 Java SAX 实现需额外配置。










