写点什么

为什么 Nop 平台坚持使用 XML 而不是 JSON 或者 YAML

作者:canonical
  • 2023-08-21
    北京
  • 本文字数:2579 字

    阅读完需:约 8 分钟

目前在开发领域似乎形成了一种政治正确:XML 是一种过时的技术,不应该再被广泛的使用。对于 Nop 平台大量使用 XML 来表达领域模型,有网友调侃道:信息都用 xml 表达,你这是反(潮流而)动啊。在此前的文章XML、JSON和函数AST的等价性中,我已经对 XML 和 JSON 的等价性进行了说明。基于这种等价性,在 Nop 平台中,XML 和 JSON 是自动支持双向转换的,本质上用哪种表达方式都不影响模型的语义,完全可以用 JSON 文件来存储模型信息。但是,目前的情况下,XML 的表现力相比 JSON 格式而言存在一些优势,在本文中我将补充一些具体的分析。

JSON 存在的问题

JSON 格式的主要问题是缺少注释机制以及多行文本表示形式。这些问题在 YAML 格式中已经被解决,而 YAML 格式兼容 JSON 格式。所以在 Nop 平台中我们一般倾向于使用 YAML 格式来替代 JSON,例如使用 page.yaml 来存放前端 JSON 页面。


x:gen-extends: |  <web:GenPage view="NopAuthUser.view.xml" page="main" xpl:lib="/nop/web/xlib/web.xlib" />
body: name: crud-grid filter: id: crud-filter actions: - id: submit-button icon: fa fa-snapchat
复制代码


在 XML 中嵌入 JSON 格式是非常简单的一件事情。但是在 JSON 中嵌入 XML 就需要进行字符串转义,会大大影响数据的可读性。如果使用 YAML 格式,嵌入 XML 就很简单直观了。


JSON 乃至 YAML 格式所存在的另一个问题是它缺少特殊定义的类型属性。JSON 对象中所有的属性原则上地位是平等的,在 JSON 规范中并没有规定可以用于快速区分 JSON 对象结构的类型属性,这导致它在反序列化的时候难以进行性能优化。


反序列化的时候我们往往需要根据类型属性来决定反序列化得到的对象类型,但是因为 JSON 格式没有规定 type 属性一定是第一个属性,可能在解析完整个对象结构之后才能对类型数据做出判断,这导致无谓的临时对象构建过程和额外的内存消耗。


相比较而言,XML 总是突出 tagName 这个特殊属性,可以帮助我们在视觉层面快速识别特定的局部结构。在简单结构的情况下,XML 表达形式可能会比 JSON 格式更简洁、直观。


 <row a="1" b="xyz" />
{ "a": 1, "b": "xyz", "type": "row" }
复制代码

XML 存在的问题

毫无疑问,XML 在实际使用过程中存在一些明显的问题,最本质的原因是 XML 最早的设计目标是一种面向文本数据的标签语言,对于具有丰富数据类型的应用数据缺乏规范化的表达方式。以 IBM、SUN 为首的大企业所大力推行的一系列 XML 相关标准又以严谨为名引入了大量复杂的设计,逐步成就了 XML 冗长繁琐的刻板印象。


XSD(XML Schema Definition)语言为例,如果对比 JSON Schema 语言,我们可以很容易的得到结论:XML Schema 的信息密度远比 JSON Schema 要低。


JSON Schema 可以很自然的声明嵌套结构,而 XML Schema 却强制把一切结构都拆解为 type 和 element 两层结构。


<xs:element name="personinfo">  <xs:complexType>    <xs:sequence>      <xs:element name="firstname" type="xs:string"/>      <xs:element name="lastname" type="xs:string"/>      <xs:element name="address" type="xs:string"/>    </xs:sequence>  </xs:complexType></xs:element>
复制代码


很多人在使用 XSD 的时候还总是倾向于使用 xs:sequence 定义,强制为子节点引入顺序依赖,这背离了声明式编程的基本思想,在使用层面往往也没有什么实际的价值,只是带来不必要的麻烦。


声明式编程很大程度上就是要淡化顺序依赖这个概念,摆脱命令式编程所强行引入的非因果约束


而在 JSON schema 中属性之间根本就无法定义顺序关系


{  "type": "object",  "properties": {    "firstname": {      "type": "string"    },    "lastname": {      "type": "string"    },    "address": {      "type": "string"    }  }}
复制代码

Nop 平台中的 XML

Nop 平台虽然大量使用 XML 语法,但是它并没有全盘接收目前的 XML 规范标准,而是只采纳了其中一个语法和特性子集。例如 NopXML 去除了外部 Entity 支持(由此避免了很多安全漏洞),简化了名字空间概念(仅在根节点处理 xmlns 配置),去除了 Instruction 概念(仅识别根节点上的 Instruction)。 Nop 平台在解析和处理 XML 的时候也没有使用现有的 JAXB (Java Architecture for XML Binding) 技术,而是自行编写了 XML 解析器。解析得到的结果不是标准 XML 技术中所定义的 DOM 结构,而是面向应用层重新设计的 XNode 结构。


class XNode{    SourceLocation loc;    String tagName;    Map<String, ValueWithLocation> attributes;    List<XNode> children;    ValueWithLocation content;
XNode parent;}
class ValueWithLocation{ SourceLocation location; Object value;}
复制代码


XNode 结构中记录了属性和节点的源码位置,并将 attribute 和 content 的值类型修改为 Object 类型,从而克服了 XML 原始设计中只针对文本文档的缺陷,使得它可以更高效的表达复杂的业务对象结构。


Nop 平台采用 XDef 元模型语言替代了 XML Schema 的作用,它利用了前缀引导语法的设计思想,比 JSON Schema 更紧凑直观。


前缀引导语法的设计参见 DSL分层语法设计及前缀引导语法


<person firstname="!string" lastname="!string" address="string" />
复制代码


XDef 元模型定义的结构基本与它所需要约束的数据结构相似,可以看作是将具体的某个模型数据中的值替换为类型声明后得到的结果。


对于 XPath 和 Xslt 转换语法,Nop 平台同样没有采用,而是设计了替代的 XSelector 和 XTransform 语法。


更为重要的是,Nop 平台引入了 XML 格式的模板语言 XPL(XLang Template Language)。它是一个图灵完备的模板语言,支持判断、循环、标签抽象、模板元编程等概念,是 Nop 平台基于 XML 格式实现可逆计算的关键技术之一。


具体介绍参见 xpl.md


Nop 平台坚持使用 XML 文件格式最重要的原因就在于 JSON 乃至 YAML 格式缺少功能与 XPL 类似的可用于复杂结构代码生成的模板语言

XPL 的特点

  1. 具有类似 Lisp 的同像特性:XPL 为 XML 格式,输出结果也是 XML 格式

  2. 具有多种输出模式,当 outputMode=node 时会直接输出 XNode 节点,在输出的过程中会记录属性和节点的来源位置。这在代码生成和断点调试时特别有用,它意味着我们始终可以跟踪当前节点的最初源码位置,调试或者报错时可以直接定位到源码行。

  3. 支持编译期运行,本质上类似于 Lisp 中的宏的作用。

  4. 支持自定义标签库,标签库支持 Delta 定制。也就是说 XPL 模板语言支持函数级别的差量化定制。


具体示例可以参见视频 Nop平台中如果通过XBiz配置文件实现后台服务函数


发布于: 刚刚阅读数: 4
用户头像

canonical

关注

还未添加个人签名 2022-08-30 加入

还未添加个人简介

评论

发布
暂无评论
为什么Nop平台坚持使用XML而不是JSON或者YAML_json_canonical_InfoQ写作社区