The export process executes two hooks before the actual exporting
begins. The first hook, org-export-before-processing-functions
,
runs before any expansions of macros, Babel code, and include keywords
in the buffer. The second hook,
org-export-before-parsing-functions
, runs before the buffer is
parsed.
Functions added to these hooks are called with a single argument: the export backend actually used, as a symbol. You may use them for heavy duty structural modifications of the document. For example, you can remove every headline in the buffer during export like this:
(defun my-headline-removal (backend) "Remove all headlines in the current buffer. BACKEND is the export backend being used, as a symbol." (org-map-entries (lambda () (delete-region (point) (line-beginning-position 2)) ;; We need to tell `org-map-entries' to not skip over heading at ;; point. Otherwise, it would continue from _next_ heading. See ;; the docstring of `org-map-entries' for details. (setq org-map-continue-from (point))))) (add-hook 'org-export-before-parsing-functions #'my-headline-removal)
Filters are lists of functions to be applied to certain parts for a given backend. The output from the first function in the filter is passed on to the next function in the filter. The final output is the output from the final function in the filter.
The Org export process has many filter sets applicable to different
types of objects, plain text, parse trees, export options, and final
output formats. The filters are named after the element type or
object type: org-export-filter-TYPE-functions
, where TYPE
is the type targeted by the filter. Valid types are:
body | bold | babel-call |
center-block | clock | code |
diary-sexp | drawer | dynamic-block |
entity | example-block | export-block |
export-snippet | final-output | fixed-width |
footnote-definition | footnote-reference | headline |
horizontal-rule | inline-babel-call | inline-src-block |
inlinetask | italic | item |
keyword | latex-environment | latex-fragment |
line-break | link | node-property |
options | paragraph | parse-tree |
plain-list | plain-text | planning |
property-drawer | quote-block | radio-target |
section | special-block | src-block |
statistics-cookie | strike-through | subscript |
superscript | table | table-cell |
table-row | target | timestamp |
underline | verbatim | verse-block |
Here is an example filter that replaces non-breaking spaces ~ ~ in the Org buffer with ‘~’ for the LaTeX backend.
(defun my-latex-filter-nobreaks (text backend info) "Ensure \" \" are properly handled in LaTeX export." (when (org-export-derived-backend-p backend 'latex) (replace-regexp-in-string " " "~" text))) (add-to-list 'org-export-filter-plain-text-functions 'my-latex-filter-nobreaks)
A filter requires three arguments: the code to be transformed, the
name of the backend, and some optional information about the export
process. The third argument can be safely ignored. Note the use of
org-export-derived-backend-p
predicate that tests for latex
backend or any other backend, such as beamer, derived from
latex.
The Org export can filter not just for backends, but also for specific files through the ‘BIND’ keyword. Here is an example with two filters; one removes brackets from time stamps, and the other removes strike-through text. The filter functions are defined in a code block in the same Org file, which is a handy location for debugging.
#+BIND: org-export-filter-timestamp-functions (tmp-f-timestamp) #+BIND: org-export-filter-strike-through-functions (tmp-f-strike-through) #+BEGIN_SRC emacs-lisp :exports results :results none (defun tmp-f-timestamp (s backend info) (replace-regexp-in-string "&[lg]t;\\|[][]" "" s)) (defun tmp-f-strike-through (s backend info) "") #+END_SRC
Org mode export is a multi-step process that works on a temporary copy of the buffer. The export process consists of 4 major steps:
Process temporary copy of the source Org buffer 147:
org-export-before-processing-functions
(see Export hooks);
org-export-use-babel
is non-nil (default), process code
blocks:
Parse the temporary buffer, creating AST:
org-export-before-parsing-functions
(see Export hooks).
The hook functions may still modify the buffer;
org-org-with-cite-processors
is non-nil (default), determine
contributing bibliographies and record them into export options
(see Citations). The whole buffer is considered;
org-export-filter-options-functions
;
(org-data ... (heading (section (paragraph (plain-text) (bold (plain-text)))) (heading) (heading (section ...))))
Past this point, modifications to the temporary buffer no longer affect the export; Org export works only with the AST;
:with-special-rows
export option
to non-nil (see Column Width and Alignment);
org-export-filter-parse-tree-functions
. These
functions can modify the AST by side effects;
org-org-with-cite-processors
is non-nil (default), replace
citation AST nodes and ‘#+print_bibliography’ keyword AST nodes as
prescribed by the selected citation export processor (see Citation export processors).
Convert the AST to text by traversing the AST nodes, depth-first:
Post-process the exported text:
org-export-filter-body-functions
;
org-org-with-cite-processors
is non-nil (default), add
bibliography metadata, as prescribed by the citation export
processor;
org-export-filter-final-output-functions
.
Some parts of the conversion process can be extended for certain elements so as to introduce a new or revised translation. That is how the HTML export backend was extended to handle Markdown format. The extensions work seamlessly so any aspect of filtering not done by the extended backend is handled by the original backend. Of all the export customization in Org, extending is very powerful as it operates at the parser level.
For this example, make the ascii backend display the language used
in a source code block. Also make it display only when some attribute
is non-nil
, like the following:
#+ATTR_ASCII: :language t
Then extend ASCII backend with a custom “my-ascii” backend.
(defun my-ascii-src-block (src-block contents info) "Transcode a SRC-BLOCK element from Org to ASCII. CONTENTS is nil. INFO is a plist used as a communication channel." (if (not (org-export-read-attribute :attr_ascii src-block :language)) (org-export-with-backend 'ascii src-block contents info) (concat (format ",--[ %s ]--\n%s`----" (org-element-property :language src-block) (replace-regexp-in-string "^" "| " (org-element-normalize-string (org-export-format-code-default src-block info))))))) (org-export-define-derived-backend 'my-ascii 'ascii :translate-alist '((src-block . my-ascii-src-block)))
The my-ascii-src-block
function looks at the attribute above the
current element. If not true, hands over to ascii backend. If
true, which it is in this example, it creates a box around the code
and leaves room for the inserting a string for language. The last
form creates the new backend that springs to action only when
translating src-block
type elements.
To use the newly defined backend, evaluate the following from an Org buffer:
(org-export-to-buffer 'my-ascii "*Org MY-ASCII Export*")
Further steps to consider would be an interactive function, self-installing an item in the export dispatcher menu, and other user-friendly improvements. See https://orgmode.org/worg/dev/org-export-reference.html for more details.
Unless otherwise specified, each step of the export process only operates on the accessible portion of the buffer. When subtree export is selected (see The Export Dispatcher), the buffer is narrowed to the body of the selected subtree, so that the rest of the buffer text, except export keywords, does not contribute to the export output.
See transcoders and :translate-alist
in the docstrings
of org-export-define-backend
and org-export-define-derived-backend
.
See inner-template
in the docstring of org-export-define-backend
.