# 写了个简单的mdx 2.0 及mdd 2.0 的reader，用于server，能查对tired

**URL:** <https://forum.freemdict.com/t/topic/42966>\
**Category:** 技术交流与词典编修\
**Tags:** 词典软件制作\
**Created:** [2026 年1 月 23 日 03:29 UTC](https://forum.freemdict.com/t/topic/42966 "2026-01-23T03:29:09Z")\
**Posts on this page:** 20\
**Page:** 2

<div class="post-metadata">

**Author:** ![last\_idol](https://forumcdn.freemdict.com/user_avatar/forum.freemdict.com/last_idol/32/2205_2.png) [@last\_idol](https://forum.freemdict.com/u/last_idol)\
**Post date:** [2026 年1 月 24 日 12:47 UTC](https://forum.freemdict.com/t/topic/42966/22 "2026-01-24T12:47:04Z")

</div>

结构化 JSON 的确问题很多，尤其是样式层和数据层容易混在一起，这点你说得对。我之前没展开，是因为一个真正通用的 JSON schema 需要反复推敲需要有取舍，我现在也还是很纠结。

但我仍然倾向于 JSON，而不是继续沿用 XML/HTML。原因很现实：XML/HTML 的设计停留在前 AI 时代，它们不具备强语法约束，也不利于结构化处理，而 JSON 天生适合被 AI 理解、生成和校验，能衍生出更多新的玩法，吸引新的用户和开发者。

如果我们再做一个新的 MDict，本质上还是旧生态的延续，老用户不会迁移，新用户也不会加入。选择 JSON 不是因为它完美，而是因为它能支撑一个面向未来的生态，而不是复制过去的格式。

---

<div class="post-metadata">

**Author:** ![wynick27](https://forumcdn.freemdict.com/letter_avatar_proxy/v4/letter/w/958977/32.png) [@wynick27](https://forum.freemdict.com/u/wynick27)\
**Post date:** [2026 年1 月 24 日 13:19 UTC](https://forum.freemdict.com/t/topic/42966/23 "2026-01-24T13:19:04Z")

</div>

问题是最终词典要显示的，而显示是绕不开html的，用json最后也得转成html，而xml有schema，xpath可以验证格式提取数据，html可以用css selector选择数据，可以给词典搭配一个metadata文件，指定常用字段，比如发音，词性的xpath，方便提取数据。而json的一大致命缺点是他的object对应大部分编程语言里的hash map，不能保证字段是有序的，主流语言只有python和js的字典是语言规定了顺序，而且都是新版规定的，如果用json就不能直接用字典而是要扩展成复杂的写法。另外词典种类很多，很难制定一个字段标准。另外接近epub格式还可以让词典能按顺序阅读，也采用zip压缩，可以方便解压编辑修改。另外我觉得用大数据那套也不好，词典除了个别的比如wiki之类的大部分词典词条在10万以内，，但是有很深的层次结构，也不需要冗余什么的，方便最重要。

---

<div class="post-metadata">

**Author:** ![amob](https://forumcdn.freemdict.com/user_avatar/forum.freemdict.com/amob/32/14630_2.png) [@amob](https://forum.freemdict.com/u/amob)\
**Post date:** [2026 年1 月 24 日 13:29 UTC](https://forum.freemdict.com/t/topic/42966/24 "2026-01-24T13:29:39Z")

</div>

json最大的问题还是对人类可读性太差，纯机读格式，做词典编辑还是得基于XML和HTML弄（很多人做mdx都要用到的正则，对json几乎没用了），json可能只是最终的转换结果，既然要转换，何不一开始就用XML和HTML。

---

<div class="post-metadata">

**Author:** ![amob](https://forumcdn.freemdict.com/user_avatar/forum.freemdict.com/amob/32/14630_2.png) [@amob](https://forum.freemdict.com/u/amob)\
**Post date:** [2026 年1 月 24 日 13:34 UTC](https://forum.freemdict.com/t/topic/42966/25 "2026-01-24T13:34:34Z")

</div>

> [@last\_idol](#):
>
> JSON schema

> [@last\_idol](#):
>
> 结构化的 JSON，不管是想实现全文搜索，还是义项，词源，例句，引文，近反义词单独搜索都太简单了

现实是没什么人遵守，你看看yomichan词典就知道了。渴望所谓的一套程序能快速提取所有词典的特殊部分，不要仰仗于词典制作者的自觉。

---

<div class="post-metadata">

**Author:** ![amob](https://forumcdn.freemdict.com/user_avatar/forum.freemdict.com/amob/32/14630_2.png) [@amob](https://forum.freemdict.com/u/amob)\
**Post date:** [2026 年1 月 24 日 13:37 UTC](https://forum.freemdict.com/t/topic/42966/26 "2026-01-24T13:37:26Z")

</div>

JSON格式词典，只有在线网站的API会使用，除此之外，研究无数离线词典格式，几乎没人用JSON。JSON的结构化，只有词典的官方有心力雕琢这些。你说JSON格式好，那对出版方是要考虑的优点，但对民间制作者是负担。

---

<div class="post-metadata">

**Author:** ![last\_idol](https://forumcdn.freemdict.com/user_avatar/forum.freemdict.com/last_idol/32/2205_2.png) [@last\_idol](https://forum.freemdict.com/u/last_idol)\
**Post date:** [2026 年1 月 24 日 14:10 UTC](https://forum.freemdict.com/t/topic/42966/27 "2026-01-24T14:10:37Z")

</div>

只提取元数据的话，带标识的 XML/HTML 确实可以，最后结果就是类似苹果词典，苹果词典在弹窗的时候，会根据 XPATH 控制显示的内容。

但我想进一步约束义项和例句的关系时就很困难了，比如说很多词典是没有层级关系的，如果我想知道某个例句从属于哪个义项，义项从属于哪个词头就非常困难，需要反复修改源文件，如果只提取 JSON 的话，会相对简单一些，但仍然繁琐。

我之前也有过类似的想法。

> [@Wikitionary Copilot：论辞典应用支持 MCP 的必要性与技术可行性](http://forum.freemdict.com/t/topic/41977/2):
>
> 如果本身是 JSON 格式的词典，或者 HTML + JSON 格式的词典，实现 MCP 会很容易。HTML 负责完整显示，提取的 JSON 负责精简释义，或者供外部客户端使用，这样最完美。

除了结构化的优势，JSON 渲染 HTML 还有一个优势就是没有兼容问题，控制力更强类似折叠和显隐，AI 翻译完全不需要词典作者自己来实现，样式也可以使用面板让用户自己修改。

> [@wynick27](#):
>
> json的一大致命缺点是他的object对应大部分编程语言里的hash map，不能保证字段是有序的

JSON 规范里对象字段是无序语义，确实遇到过需要字段有序的情况，但很少见，真正有顺序需求的场景都会用数组，因为数组的顺序是规范保证的。

---

<div class="post-metadata">

**Author:** ![wynick27](https://forumcdn.freemdict.com/letter_avatar_proxy/v4/letter/w/958977/32.png) [@wynick27](https://forum.freemdict.com/u/wynick27)\
**Post date:** [2026 年1 月 24 日 14:31 UTC](https://forum.freemdict.com/t/topic/42966/28 "2026-01-24T14:31:18Z")

</div>

数组的问题就是必须是object的数组，然后object要把标签或和样式也放进去，所以就会产生很多冗余信息，不方便编辑。  
还是举牛津初阶的例子  
这样一个表示派生词的例子，xml是这样的

```xml
<if-gs> (<if-g><if>goes</if>, <if>going</if>, <if>went</if><pron-gs><pron-g><form/><phon>went</phon><audio>went#_gb_2</audio></pron-g></pron-gs>, <if>has gone</if><pron-gs><pron-g><form/><phon>ɡɒn</phon><audio>gone#_gb_4</audio></pron-g></pron-gs></if-g>) </if-gs>

```

它在原始json数据里是这样表示的，有非常多的冗余信息，读取也不方便

```json
"top_text": [
    {
        "tag": "if-gs",
        "path": "h-g/top-g/if-gs",
        "value": " (",
        "font_Italic": "0"
    },
    {
        "tag": "if-g",
        "path": "h-g/top-g/if-gs/if-g",
        "font_Italic": "1"
    },
    {
        "tag": "if",
        "bold": 1,
        "path": "h-g/top-g/if-gs/if-g/if",
        "color": "#000000",
        "value": "goes"
    },
    {
        "tag": "if-g",
        "path": "h-g/top-g/if-gs/if-g",
        "value": ", ",
        "font_Italic": "1"
    },
    {
        "tag": "if",
        "bold": 1,
        "path": "h-g/top-g/if-gs/if-g/if",
        "color": "#000000",
        "value": "going"
    },
    {
        "tag": "if-g",
        "path": "h-g/top-g/if-gs/if-g",
        "value": ", ",
        "font_Italic": "1"
    },
    {
        "tag": "if",
        "bold": 1,
        "path": "h-g/top-g/if-gs/if-g/if",
        "color": "#000000",
        "value": "went"
    },
    {
        "tag": "pron-g",
        "path": "h-g/top-g/if-gs/if-g/pron-gs/pron-g",
        "font_Italic": "1"
    },
    {
        "tag": "form",
        "path": "h-g/top-g/if-gs/if-g/pron-gs/pron-g/form",
        "font_Italic": "0"
    },
    {
        "tag": "phon",
        "path": "h-g/top-g/if-gs/if-g/pron-gs/pron-g/phon",
        "value": "went"
    },
    {
        "tag": "audio",
        "path": "h-g/top-g/if-gs/if-g/pron-gs/pron-g/audio",
        "value": "went#_gb_2"
    },
    {
        "tag": "pron-gs",
        "path": "h-g/top-g/if-gs/if-g/pron-gs/pron-g/audio",
        "value": "/"
    },
    {
        "tag": "if-g",
        "path": "h-g/top-g/if-gs/if-g",
        "value": ", ",
        "font_Italic": "1"
    },
    {
        "tag": "if",
        "bold": 1,
        "path": "h-g/top-g/if-gs/if-g/if",
        "color": "#000000",
        "value": "has gone"
    },
    {
        "tag": "pron-g",
        "path": "h-g/top-g/if-gs/if-g/pron-gs/pron-g",
        "font_Italic": "1"
    },
    {
        "tag": "form",
        "path": "h-g/top-g/if-gs/if-g/pron-gs/pron-g/form",
        "font_Italic": "0"
    },
    {
        "tag": "phon",
        "path": "h-g/top-g/if-gs/if-g/pron-gs/pron-g/phon",
        "value": "ɡɒn"
    },
    {
        "tag": "audio",
        "path": "h-g/top-g/if-gs/if-g/pron-gs/pron-g/audio",
        "value": "gone#_gb_4"
    },
    {
        "tag": "pron-gs",
        "path": "h-g/top-g/if-gs/if-g/pron-gs/pron-g/audio",
        "value": "/"
    },
    {
        "tag": "if-gs",
        "path": "h-g/top-g/if-gs/if-g/pron-gs/pron-g/audio",
        "value": ") ",
        "font_Italic": "0"
    }
]
},

```

---

<div class="post-metadata">

**Author:** ![hua](https://forumcdn.freemdict.com/user_avatar/forum.freemdict.com/hua/32/11090_2.png) [@hua](https://forum.freemdict.com/u/hua)\
**Post date:** [2026 年1 月 24 日 15:16 UTC](https://forum.freemdict.com/t/topic/42966/29 "2026-01-24T15:16:26Z")

</div>



---

<div class="post-metadata">

**Author:** ![last\_idol](https://forumcdn.freemdict.com/user_avatar/forum.freemdict.com/last_idol/32/2205_2.png) [@last\_idol](https://forum.freemdict.com/u/last_idol)\
**Post date:** [2026 年1 月 24 日 17:02 UTC](https://forum.freemdict.com/t/topic/42966/30 "2026-01-24T17:02:15Z")

</div>

牛津初阶这种 JSON 就算喂给大模型它也用不了。冗余信息过多，语义丢失， 数据与样式耦合，第三方想要解析和维护都很困难。

从数据表达能力上看，JSON 会更受限，它本质上只是 HTML 的一个子集，从 HTML 提取的内容必然会损失一些信息。我预计很多人会难以接受这一点，但为了获得结构化的数据、稳定的语义边界，以及与 AI 更深度的协作能力，这种取舍是值得的。

我想要的是这种：

```auto
{
  "ifs": [
    {
      "hw": "goes"
    },
    {
      "hw": "going"
    },
    {
      "hw": "went",
      "prs": [
        {
          "notation": "ipa",
          "text": "went",
          "region": "gb",
          "href": "went#_gb_2"
        }
      ]
    },
    {
      "hw": "gone",
      "label": "has",
      "prs": [
        {
          "notation": "ipa",
          "text": "ɡɒn",
          "region": "gb",
          "href": "gone#_gb_4"
        }
      ]
    }
  ]
}

```

---

<div class="post-metadata">

**Author:** ![last\_idol](https://forumcdn.freemdict.com/user_avatar/forum.freemdict.com/last_idol/32/2205_2.png) [@last\_idol](https://forum.freemdict.com/u/last_idol)\
**Post date:** [2026 年1 月 24 日 17:15 UTC](https://forum.freemdict.com/t/topic/42966/31 "2026-01-24T17:15:57Z")

</div>

JSON 确实不适合直接编辑，词典制作依然由 MDict 生态来承担更合适。新格式只需要承载最常用、最有价值的那部分词典，而不是试图复制整个旧生态。作为新格式，必须做减法，想要面面俱到反而可能会处处拉胯。

---

<div class="post-metadata">

**Author:** ![last\_idol](https://forumcdn.freemdict.com/user_avatar/forum.freemdict.com/last_idol/32/2205_2.png) [@last\_idol](https://forum.freemdict.com/u/last_idol)\
**Post date:** [2026 年1 月 24 日 17:32 UTC](https://forum.freemdict.com/t/topic/42966/32 "2026-01-24T17:32:16Z")

</div>

Yomichan 的问题就是用了 ZIP，加上兼容 HTML，谁都能打包，又难以约束词典作者的自由发挥，导致内容结构混乱、质量控制失效。类似 MDict 也这样，本来所有跳转和本地资源的链接都可以在制作阶段就完成强制校验，但都没有做。

---

<div class="post-metadata">

**Author:** ![wnabc123](https://forumcdn.freemdict.com/letter_avatar_proxy/v4/letter/w/9d8465/32.png) [@wnabc123](https://forum.freemdict.com/u/wnabc123)\
**Post date:** [2026 年1 月 24 日 17:41 UTC](https://forum.freemdict.com/t/topic/42966/33 "2026-01-24T17:41:52Z")

</div>

MDX 把 Key 和 Record 分离且分块压缩，本质上就是一种专用的列存实现。

而现在的通用列存格式（如 Parquet/Lance） 配合按 Key 排序，消除“结构冗余”的能力其实更强。在列存里，不管是 HTML 标签还是 JSON Key，重复的结构都挤在一起，Zstd 压缩起来效率很高。

再加上 Metadata/Bloom Filter 辅助 SQL 引擎（如 DuckDB） 做精准的数据跳跃，这套组合拳在架构原理上完全等同于 MDX，但赢在了标准化的高兼容性上。

---

<div class="post-metadata">

**Author:** ![wynick27](https://forumcdn.freemdict.com/letter_avatar_proxy/v4/letter/w/958977/32.png) [@wynick27](https://forum.freemdict.com/u/wynick27)\
**Post date:** [2026 年1 月 24 日 17:47 UTC](https://forum.freemdict.com/t/topic/42966/34 "2026-01-24T17:47:10Z")

</div>

这样虽然很适合程序处理，但是对应制作者来说也需要程序编辑，会提高门槛。而ai一般读文件也不要求格式，更精简的xml消耗token更少。

我的想法是用xml配合一个描述结构的xml，结构用xpath或者css selector表示，如果想要内容提取可以根据这个来处理

比如这个可以写成

```auto

<inflections xpath="if-gs">
<form xpath="./if">
<pron xpath="./following-sibling::pron-gs/pron-g”>
<phon xpath="pron" />
<audio xpath="audio" />
</pron>
</form>
</inflections>

```

这样其实可以给任意xml加上描述，而描述是可以规定字段和格式的，这样就解决了结构化问题，现有的mdx也可以用这个方式写个描述xml，其实这是xslt的简化版，xslt也是w3c标准，最新版标准可以支持xml转json，但是比较复杂。

---

<div class="post-metadata">

**Author:** ![last\_idol](https://forumcdn.freemdict.com/user_avatar/forum.freemdict.com/last_idol/32/2205_2.png) [@last\_idol](https://forum.freemdict.com/u/last_idol)\
**Post date:** [2026 年1 月 24 日 17:51 UTC](https://forum.freemdict.com/t/topic/42966/35 "2026-01-24T17:51:59Z")

</div>

你这套方案太过重量级了，比如移动端就用不了。

---

<div class="post-metadata">

**Author:** ![wnabc123](https://forumcdn.freemdict.com/letter_avatar_proxy/v4/letter/w/9d8465/32.png) [@wnabc123](https://forum.freemdict.com/u/wnabc123)\
**Post date:** [2026 年1 月 24 日 18:18 UTC](https://forum.freemdict.com/t/topic/42966/36 "2026-01-24T18:18:08Z")

</div>

DuckDB 是纯嵌入式的（类似 SQLite），没有后台守护进程，核心库编译完也就 20 MB。

它支持流式读取，查词时利用 Metadata 索引，只会加载命中数据所在的那个 Block/Page（通常几百 KB 到 1MB），并不会把整个文件读入内存。

至于资源占用，DuckDB 允许强制设定全局内存上限和最大线程数。我实测其引擎大概每个活跃线程需要 ~16MB 的 Buffer，在移动端只需限制并发数，内存开销就非常低且可控。WASM 版都能在手机浏览器里流畅跑，Native 集成只会更快。

退一步讲，DuckDB 只是个引擎。由于 Parquet/Lance 是通用标准格式，如果真觉得引擎重，开发者完全可以脱离 DuckDB 自行实现一个极简读取器。这比去解析 MDX 这种非标私有格式要容易且规范得多。

---

<div class="post-metadata">

**Author:** ![last\_idol](https://forumcdn.freemdict.com/user_avatar/forum.freemdict.com/last_idol/32/2205_2.png) [@last\_idol](https://forum.freemdict.com/u/last_idol)\
**Post date:** [2026 年1 月 25 日 01:33 UTC](https://forum.freemdict.com/t/topic/42966/37 "2026-01-25T01:33:07Z")

</div>

对比 SQLite 这个开销还是太大了。

> [@wnabc123](#):
>
> 每个活跃线程需要 ~16MB 的 Buffer

> [@wnabc123](#):
>
> 核心库编译完也就 20 MB。

---

<div class="post-metadata">

**Author:** ![last\_idol](https://forumcdn.freemdict.com/user_avatar/forum.freemdict.com/last_idol/32/2205_2.png) [@last\_idol](https://forum.freemdict.com/u/last_idol)\
**Post date:** [2026 年1 月 25 日 02:31 UTC](https://forum.freemdict.com/t/topic/42966/38 "2026-01-25T02:31:43Z")

</div>

XML 确实对词典制作者来说更加友好，但对开发者来说远不如 JSON 直接。

因为相比 JSON，XML 的自由度还是过高。JSON 是纯数据交换格式，类型系统与各语言的原生数据结构一一对应，天然友好，XML 虽然也能用于数据交换，但首先是一门描述性的语言，XML 的标签天然携带顺序语义，而原生类型普遍无序两者难以直接对应，再考虑文本和节点混合的情况，就需要引入额外的结构来表达，复杂度会进一步上升。

token 消耗一般与字节长度相关：

```auto
{"ifs":[{"hw":"goes"},{"hw":"going"},{"hw":"went","prs":[{"notation":"ipa","text":"went","region":"gb","href":"went#_gb_2"}]},{"hw":"gone","label":"has","prs":[{"notation":"ipa","text":"ɡɒn","region":"gb","href":"gone#_gb_4"}]}]}
<ifs><if><hw>goes</hw></if><if><hw>going</hw></if><if><hw>went</hw><prs><pr><notation>ipa</notation><text>went</text><region>gb</region><href>went#_gb_2</href></pr></prs></if><if><hw>gone</hw><label>has</label><prs><pr><notation>ipa</notation><text>ɡɒn</text><region>gb</region><href>gone#_gb_4</href></pr></prs></if></ifs>

```

再考虑最精简的情况：

```auto
{"ifs":[{"hw":"goes"}]}
<ifs><if><hw>goes</hw></if></ifs>

```

---

<div class="post-metadata">

**Author:** ![ppxia](https://forumcdn.freemdict.com/user_avatar/forum.freemdict.com/ppxia/32/58538_2.png) [@ppxia](https://forum.freemdict.com/u/ppxia)\
**Post date:** [2026 年1 月 25 日 13:20 UTC](https://forum.freemdict.com/t/topic/42966/39 "2026-01-25T13:20:42Z")

</div>

还是要回到需求层面，需要解决现有mdict生态什么样的痛点再决定要开发什么。非常同意提到的要做的其实是减法而不是加法。  
比方像我用mdx觉得最麻烦的是mdd和css匹配问题，而且需要多种不同设备同步（iOS/android/mac/pc），可能我最需要的只是一个能够直接解读zip包里面mdx/mdd/css的词典软件，至于里面是html还是json都没关系。  
如果有人需要的是一个能用AI chatbot输出词典数据的问答系统，可能需要的是转换数据本身更加结构化让app更好读取数据本身，至于样式标签就无所谓了。  
也有可能有人需要的是更符合现代html规范的输出（旧ie内核太老有兼容问题），可能设计的又是另一套转换或者读取规范+搭配支持现代html的app就可以了。

---

<div class="post-metadata">

**Author:** ![last\_idol](https://forumcdn.freemdict.com/user_avatar/forum.freemdict.com/last_idol/32/2205_2.png) [@last\_idol](https://forum.freemdict.com/u/last_idol)\
**Post date:** [2026 年1 月 26 日 06:56 UTC](https://forum.freemdict.com/t/topic/42966/40 "2026-01-26T06:56:34Z")

</div>

文件匹配的问题，只要软件允许加载外部文件，这种问题避免不了。我倾向于将 MDX/MDD/CSS 打包在同一个文件里，这需要一个全新的格式，或者直接使用 SQLite，ZIP 的问题是内部文件必须先解压才能使用，所以不适合体积大的文件。

结构化数据可以采用 JSON 或 XML，但从现有词典中提取这些结构并不容易。许多词典本身缺乏结构，或经过人工修改而产生大量细节问题需要处理。不过，一旦这些数据被整理出来，我相信整个词典生态都能重新焕发生机。

规范化一是可以在工具打包阶段，对 HTML 结构进行强制校验，确保其符合 XHTML 的语法规范就可以了，XHTML = HTML 的语义 + XML 的语法约束；二是可以提前检查所有跳转和链接的有效性。现在的 MDict 没有任何前置检查的工具。这样做的好处不仅可以保证用户的体验，也让开发者能够放心地使用正则对 HTML 内容进行匹配和替换，因为 XML 级别的语法约束为这一过程提供了可靠的保障。

---

<div class="post-metadata">

**Author:** ![wynick27](https://forumcdn.freemdict.com/letter_avatar_proxy/v4/letter/w/958977/32.png) [@wynick27](https://forum.freemdict.com/u/wynick27)\
**Post date:** [2026 年1 月 26 日 07:35 UTC](https://forum.freemdict.com/t/topic/42966/41 "2026-01-26T07:35:02Z")

</div>

我觉得应该允许额外的资源包和外部文件，否则修改文本数据如果有几g的图片或者音频都要重新打包。zip不是问题，只要可以把文件分割成小文件就没问题，甚至可以一个词条一个文件，然后还应该保持顺序，这方面应该参考epub。

[上一页](https://forum.freemdict.com/t/topic/42966.md?page=1)

[下一页](https://forum.freemdict.com/t/topic/42966.md?page=3)
