XSD 中的 <xs:any> 元素是“万金油”/“通配符”,允许在当前位置出现任意命名空间(或指定命名空间)的任意元素。
它常用于:可扩展点、插件机制、SOAP 消息的 header、XHTML 中嵌入 MathML/SVG、第三方扩展字段等。
基本语法
<xs:any
namespace="##any" | ##other | ##targetNamespace | ##local | 命名空间列表
processContents="lax | skip | strict" (默认 strict)
minOccurs="0" 或其他数字 (默认 1)
maxOccurs="1" 或 "unbounded" (默认 1)
/>
关键属性详解
| 属性 | 可选值 | 含义 |
|---|---|---|
| namespace | ##any | 允许任何命名空间(最宽松,最常用) |
| ##other | 允许除目标命名空间(targetNamespace)外的所有命名空间 | |
| ##targetNamespace | 只允许当前 schema 的 targetNamespace | |
| ##local | 只允许无命名空间(即不带 xmlns 的元素) | |
| “http://www.w3.org/2001/XMLSchema http://example.com/ext” | 空格分隔的具体命名空间列表 | |
| processContents | strict(默认) | 必须能在 schema 中找到这些未知元素的定义,否则验证失败 |
| lax | 如果能找到定义就验证,找不到也不报错 | |
| skip | 完全跳过验证,直接当做有效(性能最好,但最不安全) | |
| minOccurs / maxOccurs | 同普通元素 | 控制这个通配位可以出现几次 |
经典使用场景及推荐写法
| 场景 | 推荐写法 | 说明 |
|---|---|---|
| 允许完全任意扩展(最常见) | <xs:any namespace="##any" processContents="skip" minOccurs="0" maxOccurs="unbounded"/> | 几乎所有可扩展框架(Spring Beans、Maven pom、Ant build.xml)都这样写 |
| 只允许自己项目扩展,其他一律禁止 | <xs:any namespace="##targetNamespace" processContents="strict" maxOccurs="unbounded"/> | 安全且可验证 |
| 允许第三方扩展,但要尽量验证 | <xs:any namespace="##other" processContents="lax" minOccurs="0" maxOccurs="unbounded"/> | 常见于 Web Service 的 header |
| 在 XHTML 中嵌入 SVG 或 MathML | <xs:any namespace="http://www.w3.org/1998/Math/MathML http://www.w3.org/2000/svg" processContents="strict"/> | XHTML 1.1 + MathML + SVG 官方就是这样写的 |
| 允许任意无命名空间的元素(很少用) | <xs:any namespace="##local" processContents="lax"/> | 常用于旧系统迁移 |
真实例子
- 最宽松的可扩展点(Spring、MyBatis、Maven 都在用)
<xs:complexType name="PluginType">
<xs:sequence>
<xs:element name="id" type="xs:string"/>
<xs:element name="version" type="xs:string"/>
<!-- 允许插件自己塞任意配置 -->
<xs:any namespace="##any"
processContents="skip"
minOccurs="0"
maxOccurs="unbounded"/>
</xs:sequence>
</xs:complexType>
- SOAP Header 的标准写法
<xs:element name="Header">
<xs:complexType>
<xs:sequence>
<xs:any namespace="##other"
processContents="lax"
minOccurs="0"
maxOccurs="unbounded"/>
</xs:sequence>
</xs:complexType>
</xs:element>
- 只允许自己公司扩展字段
<xs:complexType name="Order">
<xs:sequence>
<xs:element name="orderId" type="xs:string"/>
<xs:element name="amount" type="xs:decimal"/>
<!-- 公司内部扩展字段必须有定义 -->
<xs:any namespace="##targetNamespace"
processContents="strict"
minOccurs="0"
maxOccurs="unbounded"/>
</xs:sequence>
</xs:complexType>
与 的对比
| 通配符 | 作用对象 | 常见位置 |
|---|---|---|
<xs:any> | 子元素 | complexType 的 sequence/choice 中 |
<xs:anyAttribute> | 属性 | complexType 的最底部 |
写法几乎一样,只是后者作用于属性。
最佳实践总结
| 场景 | 推荐组合 |
|---|---|
| 完全开放的插件/扩展点 | namespace="##any" processContents="skip" |
| 希望可验证的第三方扩展 | namespace="##other processContents="lax" |
| 自己项目内部扩展 | namespace="##targetNamespace processContents="strict" |
| 需要嵌入 SVG/MathML 等 | 明确列出那几个命名空间 + processContents="strict" |
记住一句话:
99% 的可扩展场景都直接写成<xs:any namespace="##any" processContents="skip" minOccurs="0" maxOccurs="unbounded"/>
就完事了!
有具体的可扩展结构需要写 <any> 吗?贴出来我直接给你最合适的写法。