如何将组织模式缓冲区的顶级标题导出到单独的文件?


17

如何将org-mode缓冲区的每个顶级标题导出到以相应CUSTOM_ID+(经过消毒)标题的值命名的单独文件?

假设一个缓冲区包含:

* Title of Heading 1
  :PROPERTIES:
  :CUSTOM_ID: fibrillogenesis
  :END:
  Suspendisse potenti. Mauris ac felis vel velit tristique imperdiet.  

** Sub-Heading
   Nullam rutrum.

* Another Title for Heading 2
  :PROPERTIES:
  :CUSTOM_ID: mitochondrion
  :END:
  Mauris mollis tincidunt felis.  Sed bibendum.

最终结果将是一个目录,其中包含两个文件,两个顶级标题中的每个标题一个,在导出时选择格式(HTML,LaTeX等),并具有以下文件名和内容:

  1. 第一个导出标题的文件名: fibrillogenesis-title-of-heading-1.[ext]

    导出的内容,对应于原始的第一个顶级标题:

    * Title of Heading 1
      :PROPERTIES:
      :CUSTOM_ID: fibrillogenesis
      :END:
      Suspendisse potenti. Mauris ac felis vel velit tristique imperdiet.  
    
    ** Sub-Heading 
       Nullam rutrum.
    
  2. 第二个导出标题的文件名: mitochondrion-another-title-for-heading-2.[ext]

    导出的内容,对应于原始的第二个顶级标题:

    * Another Title for Heading 2
    :PROPERTIES:
    :CUSTOM_ID: mitochondrion
    :END:
    Mauris mollis tincidunt felis.  Sed bibendum. 
    

对于任何提示,方向,伪代码或(更好的)真实代码,我将不胜感激。

Answers:


27

以下命令使您可以选择一个后端,然后将每个顶级子树导出到一个单独的文件中:

(defun org-export-all (backend)
  "Export all subtrees that are *not* tagged with :noexport: to
separate files.

Note that subtrees must have the :EXPORT_FILE_NAME: property set
to a unique value for this to work properly."
  (interactive "sEnter backend: ")
  (let ((fn (cond ((equal backend "html") 'org-html-export-to-html)
                  ((equal backend "latex") 'org-latex-export-to-latex)
                  ((equal backend "pdf") 'org-latex-export-to-pdf))))
    (save-excursion
      (set-mark (point-min))
      (goto-char (point-max))
      (org-map-entries (lambda () (funcall fn nil t)) "-noexport" 'region-start-level))))

目前html,这支持HTML(),LaTeX(latex)和PDF(pdf)导出。您可以通过在中添加更多子句来增加对更多后端的支持cond

如文档字符串所述,对于每个子树,您需要将:EXPORT_FILE_NAME:属性设置为要将其导出到的文件名。(其他选项请参见下文。)

从标题文本自动生成导出文件名

如果您不想在:EXPORT_FILE_NAME:每个顶级标题中添加属性,则可以修改org-export-all以自动根据标题文本生成文件名,:EXPORT_FILE_NAME:在导出过程中可以临时设置文件名:

(defun org-export-all (backend)
  "Export all subtrees that are *not* tagged with :noexport: to
separate files.

Subtrees that do not have the :EXPORT_FILE_NAME: property set
are exported to a filename derived from the headline text."
  (interactive "sEnter backend: ")
  (let ((fn (cond ((equal backend "html") 'org-html-export-to-html)
                  ((equal backend "latex") 'org-latex-export-to-latex)
                  ((equal backend "pdf") 'org-latex-export-to-pdf)))
        (modifiedp (buffer-modified-p)))
    (save-excursion
      (set-mark (point-min))
      (goto-char (point-max))
      (org-map-entries
       (lambda ()
         (let ((export-file (org-entry-get (point) "EXPORT_FILE_NAME")))
           (unless export-file
             (org-set-property
              "EXPORT_FILE_NAME"
              (replace-regexp-in-string " " "_" (nth 4 (org-heading-components)))))
           (funcall fn nil t)
           (unless export-file (org-delete-property "EXPORT_FILE_NAME"))
           (set-buffer-modified-p modifiedp)))
       "-noexport" 'region-start-level))))

此函数通过在标题文本中用“ _”替换空格来生成导出文件名。如果要以其他方式生成文件名,请将replace-regexp-in-stringsexp 更改为所需的任何名称。

:EXPORT_FILE_NAME:设置时生成:CUSTOM_ID:

根据以下建议,org-set-property:EXPORT_FILE_NAME:在您设置时自动设置适当的值:CUSTOM_ID:

(defadvice org-set-property (after set-export-file-name
                                   (property value) activate compile)
  (when (equal org-last-set-property "CUSTOM_ID")
    (let ((export-file-name
           (concat (org-entry-get nil "CUSTOM_ID")
                   "-"
                   (replace-regexp-in-string " " "-" (downcase (org-get-heading t t))))))
      (org-entry-put nil "EXPORT_FILE_NAME" export-file-name))))

请注意,这不会为的值添加文件扩展名,:EXPORT_FILE_NAME:但这没关系,因为在导出到特定的后端时,org-mode 将自动为生成的文件选择正确的扩展名


附加信息

批量更新现有子树

如果需要设置:EXPORT_FILE_NAME:属性的现有子树数量很多,则可以使用键盘宏。在第一个子树上定位点,然后执行以下操作:

  • F3

    ...开始录音。

  • C-c C-x p CUSTOM_ID RET RET

    ...使Emacs :EXPORT_FILE_NAME:基于:CUSTOM_ID:

  • C-c C-f

    ...移至下一个顶级标题。

  • F4

    ...停止录制。

要为下一个子树重复该宏,请按F4。要为所有剩余的子树重复该宏,请按M-0 F4(为零)。

保存宏以备将来使用

默认情况下,键盘宏不会跨会话保存。要将宏存储在您的init文件中以供以后使用,请执行以下操作:

  1. 命名宏:

    M-x name-last-kbd-macro RET org-set-export-file-name RET

  2. 找到您的初始化文件,然后移至您要插入宏的位置。

  3. 插入宏:

    M-x insert-kbd-macro RET org-set-export-file-name RET

    Emacs将在以下位置插入以下代码:

    (fset 'org-set-export-file-name
       "\C-c\C-xpCUSTOM_ID\C-m\C-m\C-c\C-f")

    如果用力地斜视,您会看到第二个参数fset包含录制宏时按下的键序列:)

  4. (可选)为了获得最佳结果,您可能希望绑定org-set-export-file-name到键:

    (define-key org-mode-map (kbd "<f6>") 'org-set-export-file-name)
  5. 保存。


1
真好 您能否提示我如何以编程方式将每个标题的:EXPORT_FILE_NAME:属性设置:CUSTOM_ID:+heading-title-lowercased为?
gsl 2014年

1
@gsl您建议org-set-property设置时自动生成该:EXPORT_FILE_NAME:属性:CUSTOM_ID:
itsjeyd 2014年

1
谢谢你的建议!我不太会流利elisp,但是我会尝试的。我需要找出如何捕获每个标题的标题,用破折号代替空白,将其转换为小写字母,将经过清理的字符串添加到:CUSTOM_ID:最后设置org属性的方法。
gsl 2014年

1
@gsl我defadvice在回答中添加了一个:EXPORT_FILE_NAME:<custom-id>-<heading>当您设置时会自动设置为:CUSTOM_ID:
itsjeyd 2014年

1
非常感谢您,我从您的代码中学到了很多。如果已经有一个设置org-modeCUSTOM_IDs 的文件,那么如何运行代码来设置“ EXPORT_FILE_NAME”?不会有新的插入。我猜defadvice是行不通的吗?是否有循环功能可遍历所有顶级标题并将代码应用于它们?
gsl
By using our site, you acknowledge that you have read and understand our Cookie Policy and Privacy Policy.
Licensed under cc by-sa 3.0 with attribution required.