如何在组织模式下引用代码块点?

How to reference a code block points in org mode?

我想使用 libxml-parse-html-region 来测试一些 HTML 提取函数。但它只接受区域点作为输入参数。 Org 模式是否提供了一种将另一个代码块引用为 region 的方法?

例如

#+Name: html-test
#+BEGIN_EXAMPLE
<html>
<body>test</body>
</html>
#+END_EXAMPLE

#+BEGIN_SRC elisp
(libxml-parse-html-region html-test-start-point html-test-end-point)
#+END_SRC

那么,如何设置 html-test-start-pointhtml-test-end-point

查阅手册后,我怀疑没有简单的方法可以实现。

您可以使用其他块作为参数,如 https://orgmode.org/worg/org-contrib/babel/intro.html#arguments-to-source-code-blocks,但是 libxml 没有接受字符串的函数。

#+name: html-test
#+begin_example
<html>
<body>test</body>
</html>
#+end_example

#+begin_src elisp :var html=html-test 
(message html)
#+end_src

org-element 库(Org 模式的官方解析器)提供了将块主体作为字符串获取的功能。然后您可以将该字符串插入临时缓冲区,其中由 (point-min)(point-max) 指定的区域恰好包含块的主体。您可以在 Worg.

上找到该库的开发人员文档

由于您没有准确指定接口,我在这里只能提供一些指导。基本思想是以某种方式将点设置到示例块的开头(可能通过搜索名称 html-test 然后移动到行的开头)。到达那里后,您调用 org-element-at-point 来解析元素(也许 sanity-check 您在示例块中)。从解析树中,提取 :value 属性 的值作为字符串作为块的主体。创建一个临时缓冲区,插入字符串,然后在临时缓冲区的上下文中执行 libxml 函数。

这里是一些说明性代码,评论相当自由,我希望以一种启发性的方式(对于神秘的 (goto-char 130),请继续阅读 - 它在下面完整的 Org 模式文件中有解释):

  (save-excursion
    ;; this should probably be replaced by a search for the correct place
    (goto-char 130)
    ;; parse the element at point
    (setq parsed (org-element-at-point))
    ;; check that it is an example block
    (unless (eq (org-element-type parsed) 'example-block)
      (error "Not an example block"))
    ;; retrieve the :value property, i.e, the body of the block
    (setq value (org-element-property :value parsed))
    ;; create a temp buffer
    (with-temp-buffer
      ;; in the context of the temp buffer, insert the body of the block
      (insert value)
      ;; do something with the region containing the body by using (point-min)
      ;; as the beginning of the region and (point-max) as the end
      (message (buffer-substring (point-min) (point-max)))
      (libxml-parse-html-region (point-min) (point-max))))

这是与 Org 模式文件中的代码块相同的代码,其中包含代码块可以操作的示例块。 Cut-and-paste 将整个内容放入一个 foo.org 文件中,在 emacs 中打开它并在代码块上 C-c C-c 以查看它的运行情况:

* foo

We have a named block and we want to get the beginning and the end of the region
that consists of the body of the block.

#+Name: html-test
#+BEGIN_EXAMPLE
<html>
<body>test</body>
</html>
#+END_EXAMPLE

The position of the beginning of the block is 130 - you can check by evaluating
this expression with C-x C-e after the closing paren:

(goto-char 130)

You should end up at the beginning of the `#+name:` line.

If we imagine a code block like this:

#+BEGIN_SRC elisp
(libxml-parse-html-region html-test-start-point html-test-end-point)
#+END_SRC

the question is how to calculate the html-test-{start,end}-point values.

The suggested solution is to copy the body of the block to a temporary
buffer and do the evaluation of the XML function in that buffer. The region
is then delimited by (point-min) and (point-max).

* Code                                                                                                        :noexport:

#+begin_src elisp :results drawer
  (save-excursion
    ;; this should probably be replaced by a search for the correct place
    (goto-char 130)
    ;; parse the element at point
    (setq parsed (org-element-at-point))
    ;; check that it is an example block
    (unless (eq (org-element-type parsed) 'example-block)
      (error "Not an example block"))
    ;; retrieve the :value property, i.e, the body of the block
    (setq value (org-element-property :value parsed))
    ;; create a temp buffer
    (with-temp-buffer
      ;; in the context of the temp buffer, insert the body of the block
      (insert value)
      ;; do something with the region containing the body by using (point-min)
      ;; as the beginning of the region and (point-max) as the end
      (message (buffer-substring (point-min) (point-max)))
      (libxml-parse-html-region (point-min) (point-max))))
#+end_src

正如OP在评论中指出的和@TianshuWang在他的回答中所描述的,您可以在源代码块中添加一个变量并直接获取示例块的主体:

#+begin_src elisp :results drawer :var value=html-test

    ;; create a temp buffer
    (with-temp-buffer
      ;; in the context of the temp buffer, insert the body of the block
      (insert value)
      ;; do something with the region containing the body by using (point-min)
      ;; as the beginning of the region and (point-max) as the end
      (message (buffer-substring (point-min) (point-max)))
      (libxml-parse-html-region (point-min) (point-max))))
#+end_src

但这绕过了 org-element 库:那有什么好玩的? :-)