- html - 出于某种原因,IE8 对我的 Sass 文件中继承的 html5 CSS 不友好?
- JMeter 在响应断言中使用 span 标签的问题
- html - 在 :hover and :active? 上具有不同效果的 CSS 动画
- html - 相对于居中的 html 内容固定的 CSS 重复背景?
org-element-parse-buffer
即使对于一个小的 Org 文件,也会返回一棵巨大的树。我想将这棵树转换成 JSON。显然,json.el
使用递归函数遍历 cons 单元,因为 Elisp 不支持 tail recursion , json-encode
的调用很快就用完了堆栈。如果我增加 max-lisp-eval-depth
和 max-specpdl-size
,Emacs 会崩溃。
我该如何解决这个问题并将巨大的树结构转换为 JSON?一般来说,当我有一个庞大的数据结构和一个可能会用完堆栈的递归函数时,我该如何解决?
最佳答案
是的,json.el
函数是递归的,但是在 Org-Element 上调用的递归函数导致堆栈溢出不是因为 org-element-parse-buffer
返回一个巨大的 AST,但因为它返回一个 circular list .循环列表上的树递归函数就像笼子里的松鼠。
我想,在 AST 返回中使用自引用背后的想法是,如果你遍历它,在任何时候你都可以通过简单地运行 plist-get
返回到父级。关于关键字 :parent
.我想象这种上下遍历 AST 的用法:
(let ((xs '#1=(:text "foo" :child (:text "bar" :parent #1#))))
(plist-get
(plist-get
xs
:child) ; (:text "bar" :parent (:text "foo" :child #0))
:parent)) ; (:text "foo" :child (:text "bar" :parent #0))
但 JSON 不支持循环列表,因此在尝试转换为任何数据序列化格式之前,您需要从 AST 中删除这些自引用。我还没有找到优雅地删除 AST 中的循环引用的方法,所以我求助于一个肮脏的 hack:
假设我有一个名为 test.org
的组织文件内容如下:
* Heading
** Subheading
Text
然后变量tree
包含从此缓冲区解析的组织数据:(setq tree (with-current-buffer "test.org" (org-element-parse-buffer)))
.然后为 JSON 导出准备此数据,我只需运行:
(car (read-from-string (replace-regexp-in-string ":parent #[0-9]+?" "" (prin1-to-string tree)))))
即使所有提及 :parent
删除后,新的 AST 仍然有效,因此如果新的 AST 在变量 tree2
中, 那么下面3个表达式是等价的:
(org-element-interpret-data tree2)
(with-current-buffer "test.org" (buffer-substring-no-properties 1 (buffer-end 1)))
"* Heading\n** Subheading\nText\n"
请注意,出于某种原因 org-element-interpret-data
删除前面的空格,所以当你有像 text
这样的行时,上面的内容在技术上是不正确的在您的组织文件中。
现在您需要做的就是将新的非循环 AST 编码为 JSON 并将其写入文件:
(f-write (json-encode tree2) 'utf-8 "test.json")
Elisp 的 cons cells是成对的 2 个插槽:car
和 cdr
.如果cdr
每个单元格包含到另一个 cons 单元格的链接,我们得到一个链表。如果两个car
和 cdr
指向 2 个值,我们得到一个点对。因此(1 . (2 . (3 . nil)))
相当于(1 2 3)
.但是一个cdr
(或 car
就此而言)可能指向任何其他 cons 单元格,包括已经在列表中较早的单元格,从而产生 circular linked list .
练习:创建一个复杂的树数据结构,其中包含对不同子树的多个自引用。然后尝试遍历这棵树并通过自引用跳转以获得想法。
(->> tree prin1-to-string (replace-regexp-in-string ":parent #[0-9]+?" "") read-from-string car)
(buffer-substring-no-properties 1 (buffer-end 1))
就像(buffer-string)
, 但没有烦人 text properties附上。
关于json - 如何将庞大的 Elisp 数据结构转换为 JSON?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/28970943/
我是一名优秀的程序员,十分优秀!