目录
XDef 元模型体系:DSL 的定义语言
可逆计算要求所有业务结构以 DSL 形式存在1)。但问题来了:谁来定义 DSL 本身的结构?这就是 XDef 的角色。
XDef(XML Definition)是 Nop 平台中用来定义 DSL 语法的元模型语言。它描述了一个 DSL 文件可以有哪些节点、属性、子元素、数据类型等。基于 XDef,平台可以自动推导出解析器、验证器、IDE 插件、差量合并规则。
为什么需要元模型
传统的 DSL 实现方式是为每个语言手写解析器:
- SQL → 手写 SQL 解析器(antlr/yacc)
- JSON → 手写 JSON 解析器
- XML Schema → 手写 XSD 解析器
每个 DSL 都要重复“写解析器 → 写验证器 → 写编辑器插件”这个流程,成本很高。
Nop 的解决思路:所有 DSL 共享同一种元模型描述。只要写好 XDef,配套工具自动生成。
XDef 示例
下面是一个 .xdef 文件片段,它定义了 ORM 实体模型(orm.xml)的语法:
<entity name="string" table="string">
<columns>
<column name="string" code="string"
primary="boolean" mandatory="boolean">
<comment text="string" />
</column>
</columns>
</entity>
这个 XDef 描述的意思是:
- 根节点叫 entity,有两个必需属性 name(字符串)和 table(字符串)
- entity 包含一个 columns 子节点
- columns 包含若干个 column 子节点
- column 有 name、code、primary、mandatory 等属性
- column 可以包含 comment 子节点
基于这几十行定义,平台自动获得:
- 解析器:验证输入 XML 是否符合结构要求
- 验证器:检查类型、必填、枚举值约束
- IDE 支持:语法提示、自动补全、文件跳转
- 差量合并规则:哪些元素可以覆盖、哪些可以删除
内置类型系统
XDef 内置了一套完整的数据类型:
| 类型 | 说明 |
|---|---|
| string | 字符串 |
| boolean | 布尔值 |
| integer | 整数 |
| double | 浮点数 |
| decimal | 高精度小数(BigDecimal) |
| date | 日期 |
| datetime | 日期时间 |
| enum | 枚举值(配合 option 使用) |
| xml | 内嵌 XML 片段 |
| csv | 逗号分隔列表 |
还可以通过 xdef:check 扩展自定义验证逻辑。
继承与复用
XDef 支持元模型级别的复用机制:
- xdef:base — 继承另一个 XDef 定义
- xdef:ref — 引用已定义的结构
- xdef:name — 为节点命名,便于其他 XDef 引用
这意味着可以定义基础 XDef,然后在具体 DSL 中扩展。例如,所有业务模型的 XDef 都继承自一个公共的基础 XDef,统一了 id、name、label 等公共属性的定义。
从 XDef 到 DSL 的工作流
定义一个 Nop 平台 DSL 的完整流程:
- 编写 .xdef 文件(一人工作量,几小时到数天)
- 平台自动生成解析器、验证器、合并规则(自动)
- 编写 .xdsl 文件(具体的 DSL 实例,如 orm.xml)
- 平台加载 xdsl 时通过 x-extends 合并所有 Delta 层(自动)
- Generator 读取合并后的模型,生成 Java 代码、SQL、前端页面(自动)
.xdef(元模型)→ 解析器 + 验证器 + IDE 插件(自动生成)
↓
.xdsl(具体模型文件)→ 经过 x-extends 合并
↓
Generator → Java / SQL / GraphQL / 前端
整个过程,手写部分只有 .xdef 和 .xdsl 文件。
XDef 与 XSD/JSON Schema 的对比
| 对比维度 | XSD | JSON Schema | XDef |
|---|---|---|---|
| 语法复杂度 | 繁琐 | 中等 | 简洁 |
| 差量合并 | 不支持 | 不支持 | 内置 |
| IDE 生成 | 需要额外工具 | 需要额外工具 | 自动 |
| 已定义 DSL 数量 | 少数 | 少数 | 数百个 |
| 与生成器集成 | 无 | 无 | 原生 |
XDef 的设计目标并非替代 XSD/JSON Schema,而是为可逆计算中的 DSL 体系提供统一的元模型基础。差量合并和代码生成才是它的核心价值。