emacs-orgmode
[Top][All Lists]
Advanced

[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]

Re: [O] [RFC] Changing internal representation of back-ends to defstruct


From: Carsten Dominik
Subject: Re: [O] [RFC] Changing internal representation of back-ends to defstructs
Date: Wed, 3 Jul 2013 23:48:54 +0200

Hi Nicolas,

this does look like a good change - and hopefully few enough external backends
have been written for this patch to not pose a problem.

- Carsten

On 3.7.2013, at 22:57, Nicolas Goaziou <address@hidden> wrote:

> Hello,
> 
> Currently, a back-end is a symbol which may point to an entry in
> `org-export-registered-backends' variable. Therefore a back-end must be
> registered (with a unique name) before one can call it. Or, to put it
> differently, it is impossible to use an anonymous and temporary
> back-end.
> 
> This is not satisfying for developers, as there are situations when you
> need to use a one-shot back-end but don't want to clutter registered
> back-ends list. You can of course let-bind
> `org-export-registered-backends' to something else, but it leads to
> clunky code. The process should be abstracted a bit more.
> 
> The following (long) patches address this by defining back-ends as
> structures (see `defstruct'), possibly anonymous and by separating
> creation from registration process. It allows to quickly create and use
> temporary back-ends. In the example below, we quickly export a string
> using a temporary back-end:
> 
>  (org-export-string-as
>   "* H1\n** H2\nSome string"
>   (org-export-create-backend
>    :transcoders
>    '((headline . (lambda (h contents i)
>                    (let ((m (make-string (org-export-get-relative-level h i) 
> ?=)))
>                      (concat m " " (org-element-property :raw-value h) " " m 
> "\n"
>                              contents))))
>      ;; Contents only.
>      (section . (lambda (e c i) c))
>      (paragraph . (lambda (e c i) c)))))
> 
> It is also possible to create a temporary derived back-end. The
> following export will use registered `latex' back-end, excepted for
> `bold' type objects.
> 
>  (org-export-string-as
>     "Some *bold* /string/"
>     (org-export-create-backend
>      :parent 'latex
>      :transcoders '((italic . (lambda (o c i) (format "\\texit{%s}" c)))))
>     'body-only)
> 
> Besides `org-export-create-backend', tools provided are:
> - `org-export-get-backend'
> - `org-export-register-backend'
> - `org-export-get-all-transcoders' (handles inheritance)
> - `org-export-get-all-options' (handles inheritance)
> - `org-export-get-all-filters' (handles inheritance)
> 
> At a higher level, `org-export-define-backend' and
> `org-export-define-derived-backend' do not change (they are equivalent
> to create and register in a row). So this change only matters for
> back-end developers who used advanced features like
> `org-export-with-translations' (which should now be
> `org-export-with-backend' coupled with an anonymous back-end).
> 
> Also, it leads to a cleaner implementation as it removes the confusion
> between a back-end and its name.
> 
> The next step after applying this patch will be to make
> orgtbl-to-BACKEND functions use anonymous functions in order to
> support :splice property, which is tedious with the new export
> framework.
> 
> Feedback welcome.
> 
> 
> Regards,
> 
> -- 
> Nicolas Goaziou
> From 35bf951a1cd4c455f01863e128a899d36e76a76c Mon Sep 17 00:00:00 2001
> From: Nicolas Goaziou <address@hidden>
> Date: Mon, 24 Jun 2013 20:52:10 +0200
> Subject: [PATCH 1/2] ox: Change back-ends internal representation to
> structures
> 
> * lisp/ox.el (org-export--registered-backends): Renamed from
>  `org-export-registered-backends'.
> (org-export-invisible-backends): Removed variable.
> (org-export-get-backend, org-export-get-all-transcoders
> org-export-get-all-options, org-export-get-all-filters): New
> functions.  It replaces `org-export-backend-translate-table'.
> (org-export-barf-if-invalid-backend, org-export-derived-backend-p,
> org-export-define-backend, org-export-define-derived-backend):
> Rewrite functions using new representation.
> (org-export-backend-translate-table): Remove function.
> (org-export-get-environment): Use new function.
> (org-export--get-subtree-options, org-export--parse-option-keyword,
> org-export--get-inbuffer-options, org-export--get-global-options,
> org-export-to-buffer org-export-to-file, org-export-string-as
> org-export-replace-region-by): Update docstring.
> (org-export-data-with-translations): Remove function.  Use
> `org-export-data-with-backend' with a temporary back-end instead.
> (org-export-data-with-backend, org-export-as): Reflect new definition
> for back-ends.
> (org-export--dispatch-action, org-export--dispatch-ui): Reflect new
> definition for back-ends and variable removal.  Refactoring.
> (org-export-filter-apply-functions): Call functions with
> current back-end's name, not full back-end.
> * lisp/org.el (org-export-backends, org-create-formula--latex-header):
> Use new structure and variables.
> * testing/lisp/test-ox.el: Update tests.
> 
> This patch separates back-end definition from its registration.  Thus,
> it allows to use anonymous or unregistered back-ends.
> ---
> lisp/org.el             |  58 ++--
> lisp/ox.el              | 527 +++++++++++++++++---------------
> testing/lisp/test-ox.el | 781 +++++++++++++++++++++++++++---------------------
> 3 files changed, 764 insertions(+), 602 deletions(-)
> 
> diff --git a/lisp/org.el b/lisp/org.el
> index 6233972..89cc328 100644
> --- a/lisp/org.el
> +++ b/lisp/org.el
> @@ -436,8 +436,9 @@ For export specific modules, see also 
> `org-export-backends'."
>       (const :tag "C  wl:                Links to Wanderlust 
> folders/messages" org-wl)
>       (repeat :tag "External packages" :inline t (symbol :tag "Package"))))
> 
> -(defvar org-export-registered-backends)      ; From ox.el
> +(defvar org-export--registered-backends) ; From ox.el.
> (declare-function org-export-derived-backend-p "ox" (backend &rest backends))
> +(declare-function org-export-backend-name "ox" (backend))
> (defcustom org-export-backends '(ascii html icalendar latex)
>   "List of export back-ends that should be always available.
> 
> @@ -451,30 +452,29 @@ needed.
> 
> This variable needs to be set before org.el is loaded.  If you
> need to make a change while Emacs is running, use the customize
> -interface or run the following code, where VALUE stands for the
> -new value of the variable, after updating it:
> +interface or run the following code, where VAL stands for the new
> +value of the variable, after updating it:
> 
>   \(progn
> -    \(setq org-export-registered-backends
> +    \(setq org-export--registered-backends
>           \(org-remove-if-not
>            \(lambda (backend)
> -             \(or (memq backend val)
> -                 \(catch 'parentp
> -                   \(mapc
> -                    \(lambda (b)
> -                      \(and (org-export-derived-backend-p b (car backend))
> -                           \(throw 'parentp t)))
> -                    val)
> -                   nil)))
> -           org-export-registered-backends))
> -    \(let ((new-list (mapcar 'car org-export-registered-backends)))
> +             \(let ((name (org-export-backend-name backend)))
> +               \(or (memq name val)
> +                   \(catch 'parentp
> +                     \(dolist (b val)
> +                       \(and (org-export-derived-backend-p b name)
> +                            \(throw 'parentp t)))))))
> +           org-export--registered-backends))
> +    \(let ((new-list (mapcar 'org-export-backend-name
> +                            org-export--registered-backends)))
>       \(dolist (backend val)
>         \(cond
>          \((not (load (format \"ox-%s\" backend) t t))
>           \(message \"Problems while trying to load export back-end `%s'\"
>                    backend))
>          \((not (memq backend new-list)) (push backend new-list))))
> -      \(set-default var new-list)))
> +      \(set-default 'org-export-backends new-list)))
> 
> Adding a back-end to this list will also pull the back-end it
> depends on, if any."
> @@ -488,21 +488,20 @@ depends on, if any."
>          ;; Any back-end not required anymore (not present in VAL and not
>          ;; a parent of any back-end in the new value) is removed from the
>          ;; list of registered back-ends.
> -        (setq org-export-registered-backends
> +        (setq org-export--registered-backends
>                (org-remove-if-not
>                 (lambda (backend)
> -                 (or (memq backend val)
> -                     (catch 'parentp
> -                       (mapc
> -                        (lambda (b)
> -                          (and (org-export-derived-backend-p b (car backend))
> -                               (throw 'parentp t)))
> -                        val)
> -                       nil)))
> -               org-export-registered-backends))
> +                 (let ((name (org-export-backend-name backend)))
> +                   (or (memq name val)
> +                       (catch 'parentp
> +                         (dolist (b val)
> +                           (and (org-export-derived-backend-p b name)
> +                                (throw 'parentp t)))))))
> +               org-export--registered-backends))
>          ;; Now build NEW-LIST of both new back-ends and required
>          ;; parents.
> -        (let ((new-list (mapcar 'car org-export-registered-backends)))
> +        (let ((new-list (mapcar 'org-export-backend-name
> +                                org-export--registered-backends)))
>            (dolist (backend val)
>              (cond
>               ((not (load (format "ox-%s" backend) t t))
> @@ -18494,14 +18493,17 @@ share a good deal of logic."
>          "Invalid value of `org-latex-create-formula-image-program'")))
>    string tofile options buffer))
> 
> +(declare-function org-export-get-backend "ox" (name))
> (declare-function org-export--get-global-options "ox" (&optional backend))
> (declare-function org-export--get-inbuffer-options "ox" (&optional backend))
> (declare-function org-latex-guess-inputenc "ox-latex" (header))
> (declare-function org-latex-guess-babel-language "ox-latex" (header info))
> (defun org-create-formula--latex-header ()
>   "Return LaTeX header appropriate for previewing a LaTeX snippet."
> -  (let ((info (org-combine-plists (org-export--get-global-options 'latex)
> -                               (org-export--get-inbuffer-options 'latex))))
> +  (let ((info (org-combine-plists (org-export--get-global-options
> +                                (org-export-get-backend 'latex))
> +                               (org-export--get-inbuffer-options
> +                                (org-export-get-backend 'latex)))))
>     (org-latex-guess-babel-language
>      (org-latex-guess-inputenc
>       (org-splice-latex-header
> diff --git a/lisp/ox.el b/lisp/ox.el
> index 92ad356..71435b7 100644
> --- a/lisp/ox.el
> +++ b/lisp/ox.el
> @@ -47,15 +47,10 @@
> ;; The core function is `org-export-as'.  It returns the transcoded
> ;; buffer as a string.
> ;;
> -;; An export back-end is defined with `org-export-define-backend',
> -;; which defines one mandatory information: his translation table.
> -;; Its value is an alist whose keys are elements and objects types and
> -;; values translator functions.  See function's docstring for more
> -;; information about translators.
> -;;
> -;; Optionally, `org-export-define-backend' can also support specific
> -;; buffer keywords, OPTION keyword's items and filters.  Also refer to
> -;; function documentation for more information.
> +;; An export back-end is defined with `org-export-define-backend'.
> +;; This function can also support specific buffer keywords, OPTION
> +;; keyword's items and filters.  Refer to function's documentation for
> +;; more information.
> ;;
> ;; If the new back-end shares most properties with another one,
> ;; `org-export-define-derived-backend' can be used to simplify the
> @@ -280,14 +275,8 @@ containing the back-end used, as a symbol, and either a 
> process
> or the time at which it finished.  It is used to build the menu
> from `org-export-stack'.")
> 
> -(defvar org-export-registered-backends nil
> +(defvar org-export--registered-backends nil
>   "List of backends currently available in the exporter.
> -
> -A backend is stored as a list where CAR is its name, as a symbol,
> -and CDR is a plist with the following properties:
> -`:filters-alist', `:menu-entry', `:options-alist' and
> -`:translate-alist'.
> -
> This variable is set with `org-export-define-backend' and
> `org-export-define-derived-backend' functions.")
> 
> @@ -830,20 +819,6 @@ process faster and the export more portable."
>   :package-version '(Org . "8.0")
>   :type '(file :must-match t))
> 
> -(defcustom org-export-invisible-backends nil
> -  "List of back-ends that shouldn't appear in the dispatcher.
> -
> -Any back-end belonging to this list or derived from a back-end
> -belonging to it will not appear in the dispatcher menu.
> -
> -Indeed, Org may require some export back-ends without notice.  If
> -these modules are never to be used interactively, adding them
> -here will avoid cluttering the dispatcher menu."
> -  :group 'org-export-general
> -  :version "24.4"
> -  :package-version '(Org . "8.0")
> -  :type '(repeat (symbol :tag "Back-End")))
> -
> (defcustom org-export-dispatch-use-expert-ui nil
>   "Non-nil means using a non-intrusive `org-export-dispatch'.
> In that case, no help buffer is displayed.  Though, an indicator
> @@ -863,25 +838,147 @@ mode."
> 
> ;;; Defining Back-ends
> ;;
> -;; `org-export-define-backend' is the standard way to define an export
> -;; back-end.  It allows to specify translators, filters, buffer
> -;; options and a menu entry.  If the new back-end shares translators
> -;; with another back-end, `org-export-define-derived-backend' may be
> -;; used instead.
> +;; An export back-end is a structure with `org-export-backend' type
> +;; and `name', `parent', `transcoders', `options', `filters', `blocks'
> +;; and `menu' slots.
> +;;
> +;; At the lowest level, a back-end is created with
> +;; `org-export-create-backend' function.
> +;;
> +;; A named back-end can be registered with
> +;; `org-export-register-backend' function.  A registered back-end can
> +;; later be referred to by its name, with `org-export-get-backend'
> +;; function.  Also, such a back-end can become the parent of a derived
> +;; back-end from which slot values will be inherited by default.
> +;; `org-export-derived-backend-p' can check if a given back-end is
> +;; derived from a list of back-end names.
> +;;
> +;; `org-export-get-all-transcoders', `org-export-get-all-options' and
> +;; `org-export-get-all-filters' return the full alist of transcoders,
> +;; options and filters, including those inherited from ancestors.
> ;;
> -;; Internally, a back-end is stored as a list, of which CAR is the
> -;; name of the back-end, as a symbol, and CDR a plist.  Accessors to
> -;; properties of a given back-end are: `org-export-backend-filters',
> -;; `org-export-backend-menu', `org-export-backend-options' and
> -;; `org-export-backend-translate-table'.
> +;; At a higher level, `org-export-define-backend' is the standard way
> +;; to define an export back-end.  If the new back-end is similar to
> +;; a registered back-end, `org-export-define-derived-backend' may be
> +;; used instead.
> ;;
> ;; Eventually `org-export-barf-if-invalid-backend' returns an error
> ;; when a given back-end hasn't been registered yet.
> 
> -(defun org-export-define-backend (backend translators &rest body)
> +(defstruct (org-export-backend (:constructor org-export-create-backend)
> +                            (:copier nil))
> +  name parent transcoders options filters blocks menu)
> +
> +(defun org-export-get-backend (name)
> +  "Return export back-end named after NAME.
> +NAME is a symbol.  Return nil if no such back-end is found."
> +  (catch 'found
> +    (dolist (b org-export--registered-backends)
> +      (when (eq (org-export-backend-name b) name)
> +     (throw 'found b)))))
> +
> +(defun org-export-register-backend (backend)
> +  "Register BACKEND as a known export back-end.
> +BACKEND is a structure with `org-export-backend' type."
> +  ;; Refuse to register an unnamed back-end.
> +  (unless (org-export-backend-name backend)
> +    (error "Cannot register a unnamed export back-end"))
> +  ;; Refuse to register a back-end with an unknown parent.
> +  (let ((parent (org-export-backend-parent backend)))
> +    (when (and parent (not (org-export-get-backend parent)))
> +      (error "Cannot use unknown \"%s\" back-end as a parent" parent)))
> +  ;; Register dedicated export blocks in the parser.
> +  (dolist (name (org-export-backend-blocks backend))
> +    (add-to-list 'org-element-block-name-alist
> +              (cons name 'org-element-export-block-parser)))
> +  ;; If a back-end with the same name as BACKEND is already
> +  ;; registered, replace it with BACKEND.  Otherwise, simply add
> +  ;; BACKEND to the list of registered back-ends.
> +  (let ((old (org-export-get-backend (org-export-backend-name backend))))
> +    (if old (setcar (memq old org-export--registered-backends) backend)
> +      (push backend org-export--registered-backends))))
> +
> +(defun org-export-barf-if-invalid-backend (backend)
> +  "Signal an error if BACKEND isn't defined."
> +  (unless (org-export-backend-p backend)
> +    (error "Unknown \"%s\" back-end: Aborting export" backend)))
> +
> +(defun org-export-derived-backend-p (backend &rest backends)
> +  "Non-nil if BACKEND is derived from one of BACKENDS.
> +BACKEND is an export back-end, as returned by, e.g.,
> +`org-export-create-backend', or a symbol referring to
> +a registered back-end.  BACKENDS is constituted of symbols."
> +  (when (symbolp backend) (setq backend (org-export-get-backend backend)))
> +  (when backend
> +    (catch 'exit
> +      (while (org-export-backend-parent backend)
> +     (when (memq (org-export-backend-name backend) backends)
> +       (throw 'exit t))
> +     (setq backend
> +           (org-export-get-backend (org-export-backend-parent backend))))
> +      (memq (org-export-backend-name backend) backends))))
> +
> +(defun org-export-get-all-transcoders (backend)
> +  "Return full translation table for BACKEND.
> +
> +BACKEND is an export back-end, as return by, e.g,,
> +`org-export-create-backend'.  Return value is an alist where
> +keys are element or object types, as symbols, and values are
> +transcoders.
> +
> +Unlike to `org-export-backend-transcoders', this function
> +also returns transcoders inherited from parent back-ends,
> +if any."
> +  (when (symbolp backend) (setq backend (org-export-get-backend backend)))
> +  (when backend
> +    (let ((transcoders (org-export-backend-transcoders backend))
> +       parent)
> +      (while (setq parent (org-export-backend-parent backend))
> +     (setq backend (org-export-get-backend parent))
> +     (setq transcoders
> +           (append transcoders (org-export-backend-transcoders backend))))
> +      transcoders)))
> +
> +(defun org-export-get-all-options (backend)
> +  "Return export options for BACKEND.
> +
> +BACKEND is an export back-end, as return by, e.g,,
> +`org-export-create-backend'.  See `org-export-options-alist'
> +for the shape of the return value.
> +
> +Unlike to `org-export-backend-options', this function also
> +returns options inherited from parent back-ends, if any."
> +  (when (symbolp backend) (setq backend (org-export-get-backend backend)))
> +  (when backend
> +    (let ((options (org-export-backend-options backend))
> +       parent)
> +      (while (setq parent (org-export-backend-parent backend))
> +     (setq backend (org-export-get-backend parent))
> +     (setq options (append options (org-export-backend-options backend))))
> +      options)))
> +
> +(defun org-export-get-all-filters (backend)
> +  "Return complete list of filters for BACKEND.
> +
> +BACKEND is an export back-end, as return by, e.g,,
> +`org-export-create-backend'.  Return value is an alist where
> +keys are symbols and values lists of functions.
> +
> +Unlike to `org-export-backend-filters', this function also
> +returns filters inherited from parent back-ends, if any."
> +  (when (symbolp backend) (setq backend (org-export-get-backend backend)))
> +  (when backend
> +    (let ((filters (org-export-backend-filters backend))
> +       parent)
> +      (while (setq parent (org-export-backend-parent backend))
> +     (setq backend (org-export-get-backend parent))
> +     (setq filters (append filters (org-export-backend-filters backend))))
> +      filters)))
> +
> +(defun org-export-define-backend (backend transcoders &rest body)
>   "Define a new back-end BACKEND.
> 
> -TRANSLATORS is an alist between object or element types and
> +TRANSCODERS is an alist between object or element types and
> functions handling them.
> 
> These functions should return a string without any trailing
> @@ -997,32 +1094,23 @@ keywords are understood:
>     `org-export-options-alist' for more information about
>     structure of the values."
>   (declare (indent 1))
> -  (let (export-block filters menu-entry options contents)
> +  (let (blocks filters menu-entry options contents)
>     (while (keywordp (car body))
>       (case (pop body)
>         (:export-block (let ((names (pop body)))
> -                      (setq export-block
> -                            (if (consp names) (mapcar 'upcase names)
> -                              (list (upcase names))))))
> +                      (setq blocks (if (consp names) (mapcar 'upcase names)
> +                                     (list (upcase names))))))
>       (:filters-alist (setq filters (pop body)))
>       (:menu-entry (setq menu-entry (pop body)))
>         (:options-alist (setq options (pop body)))
>         (t (pop body))))
> -    (setq contents (append (list :translate-alist translators)
> -                        (and filters (list :filters-alist filters))
> -                        (and options (list :options-alist options))
> -                        (and menu-entry (list :menu-entry menu-entry))))
> -    ;; Register back-end.
> -    (let ((registeredp (assq backend org-export-registered-backends)))
> -      (if registeredp (setcdr registeredp contents)
> -     (push (cons backend contents) org-export-registered-backends)))
> -    ;; Tell parser to not parse EXPORT-BLOCK blocks.
> -    (when export-block
> -      (mapc
> -       (lambda (name)
> -      (add-to-list 'org-element-block-name-alist
> -                   `(,name . org-element-export-block-parser)))
> -       export-block))))
> +    (org-export-register-backend
> +     (org-export-create-backend :name backend
> +                             :transcoders transcoders
> +                             :options options
> +                             :filters filters
> +                             :blocks blocks
> +                             :menu menu-entry))))
> 
> (defun org-export-define-derived-backend (child parent &rest body)
>   "Create a new back-end as a variant of an existing one.
> @@ -1077,75 +1165,25 @@ The back-end could then be called with, for example:
> 
>   \(org-export-to-buffer 'my-latex \"*Test my-latex*\")"
>   (declare (indent 2))
> -  (let (export-block filters menu-entry options translators contents)
> +  (let (blocks filters menu-entry options transcoders contents)
>     (while (keywordp (car body))
>       (case (pop body)
>       (:export-block (let ((names (pop body)))
> -                      (setq export-block
> -                            (if (consp names) (mapcar 'upcase names)
> -                              (list (upcase names))))))
> +                      (setq blocks (if (consp names) (mapcar 'upcase names)
> +                                     (list (upcase names))))))
>         (:filters-alist (setq filters (pop body)))
>       (:menu-entry (setq menu-entry (pop body)))
>         (:options-alist (setq options (pop body)))
> -        (:translate-alist (setq translators (pop body)))
> +        (:translate-alist (setq transcoders (pop body)))
>         (t (pop body))))
> -    (setq contents (append
> -                 (list :parent parent)
> -                 (let ((p-table (org-export-backend-translate-table parent)))
> -                   (list :translate-alist (append translators p-table)))
> -                 (let ((p-filters (org-export-backend-filters parent)))
> -                   (list :filters-alist (append filters p-filters)))
> -                 (let ((p-options (org-export-backend-options parent)))
> -                   (list :options-alist (append options p-options)))
> -                 (and menu-entry (list :menu-entry menu-entry))))
> -    (org-export-barf-if-invalid-backend parent)
> -    ;; Register back-end.
> -    (let ((registeredp (assq child org-export-registered-backends)))
> -      (if registeredp (setcdr registeredp contents)
> -     (push (cons child contents) org-export-registered-backends)))
> -    ;; Tell parser to not parse EXPORT-BLOCK blocks.
> -    (when export-block
> -      (mapc
> -       (lambda (name)
> -      (add-to-list 'org-element-block-name-alist
> -                   `(,name . org-element-export-block-parser)))
> -       export-block))))
> -
> -(defun org-export-backend-parent (backend)
> -  "Return back-end from which BACKEND is derived, or nil."
> -  (plist-get (cdr (assq backend org-export-registered-backends)) :parent))
> -
> -(defun org-export-backend-filters (backend)
> -  "Return filters for BACKEND."
> -  (plist-get (cdr (assq backend org-export-registered-backends))
> -          :filters-alist))
> -
> -(defun org-export-backend-menu (backend)
> -  "Return menu entry for BACKEND."
> -  (plist-get (cdr (assq backend org-export-registered-backends))
> -          :menu-entry))
> -
> -(defun org-export-backend-options (backend)
> -  "Return export options for BACKEND."
> -  (plist-get (cdr (assq backend org-export-registered-backends))
> -          :options-alist))
> -
> -(defun org-export-backend-translate-table (backend)
> -  "Return translate table for BACKEND."
> -  (plist-get (cdr (assq backend org-export-registered-backends))
> -          :translate-alist))
> -
> -(defun org-export-barf-if-invalid-backend (backend)
> -  "Signal an error if BACKEND isn't defined."
> -  (unless (org-export-backend-translate-table backend)
> -    (error "Unknown \"%s\" back-end: Aborting export" backend)))
> -
> -(defun org-export-derived-backend-p (backend &rest backends)
> -  "Non-nil if BACKEND is derived from one of BACKENDS."
> -  (let ((parent backend))
> -    (while (and (not (memq parent backends))
> -             (setq parent (org-export-backend-parent parent))))
> -    parent))
> +    (org-export-register-backend
> +     (org-export-create-backend :name child
> +                             :parent parent
> +                             :transcoders transcoders
> +                             :options options
> +                             :filters filters
> +                             :blocks blocks
> +                             :menu menu-entry))))
> 
> 
> 
> @@ -1448,14 +1486,15 @@ The back-end could then be called with, for example:
> ;;  `org-export--get-subtree-options' and
> ;;  `org-export--get-inbuffer-options'
> ;;
> -;; Also, `org-export--install-letbind-maybe' takes care of the part
> -;; relative to "#+BIND:" keywords.
> +;; Also, `org-export--list-bound-variables' collects bound variables
> +;; along with their value in order to set them as buffer local
> +;; variables later in the process.
> 
> (defun org-export-get-environment (&optional backend subtreep ext-plist)
>   "Collect export options from the current buffer.
> 
> -Optional argument BACKEND is a symbol specifying which back-end
> -specific options to read, if any.
> +Optional argument BACKEND is an export back-end, as returned by
> +`org-export-create-backend'.
> 
> When optional argument SUBTREEP is non-nil, assume the export is
> done against the current sub-tree.
> @@ -1481,8 +1520,7 @@ inferior to file-local settings."
>    (list
>     :back-end
>     backend
> -    :translate-alist
> -    (org-export-backend-translate-table backend)
> +    :translate-alist (org-export-get-all-transcoders backend)
>     :footnote-definition-alist
>     ;; Footnotes definitions must be collected in the original
>     ;; buffer, as there's no insurance that they will still be in
> @@ -1518,11 +1556,12 @@ inferior to file-local settings."
> 
> (defun org-export--parse-option-keyword (options &optional backend)
>   "Parse an OPTIONS line and return values as a plist.
> -Optional argument BACKEND is a symbol specifying which back-end
> +Optional argument BACKEND is an export back-end, as returned by,
> +e.g., `org-export-create-backend'.  It specifies which back-end
> specific items to read, if any."
>   (let* ((all
>         ;; Priority is given to back-end specific options.
> -       (append (and backend (org-export-backend-options backend))
> +       (append (and backend (org-export-get-all-options backend))
>                 org-export-options-alist))
>        plist)
>     (dolist (option all)
> @@ -1542,7 +1581,8 @@ specific items to read, if any."
> 
> (defun org-export--get-subtree-options (&optional backend)
>   "Get export options in subtree at point.
> -Optional argument BACKEND is a symbol specifying back-end used
> +Optional argument BACKEND is an export back-end, as returned by,
> +e.g., `org-export-create-backend'.  It specifies back-end used
> for export.  Return options as a plist."
>   ;; For each buffer keyword, create a headline property setting the
>   ;; same property in communication channel. The name for the property
> @@ -1594,7 +1634,7 @@ for export.  Return options as a plist."
>                         (t value)))))))))
>       ;; Look for both general keywords and back-end specific
>       ;; options, with priority given to the latter.
> -     (append (and backend (org-export-backend-options backend))
> +     (append (and backend (org-export-get-all-options backend))
>               org-export-options-alist)))
>      ;; Return value.
>      plist)))
> @@ -1602,7 +1642,8 @@ for export.  Return options as a plist."
> (defun org-export--get-inbuffer-options (&optional backend)
>   "Return current buffer export options, as a plist.
> 
> -Optional argument BACKEND, when non-nil, is a symbol specifying
> +Optional argument BACKEND, when non-nil, is an export back-end,
> +as returned by, e.g., `org-export-create-backend'.  It specifies
> which back-end specific options should also be read in the
> process.
> 
> @@ -1612,7 +1653,7 @@ Assume buffer is in Org mode.  Narrowing, if any, is 
> ignored."
>        (case-fold-search t)
>        (options (append
>                  ;; Priority is given to back-end specific options.
> -                (and backend (org-export-backend-options backend))
> +                (and backend (org-export-get-all-options backend))
>                  org-export-options-alist))
>        (regexp (format "^[ \t]*#\\+%s:"
>                        (regexp-opt (nconc (delq nil (mapcar 'cadr options))
> @@ -1725,12 +1766,13 @@ name."
> 
> (defun org-export--get-global-options (&optional backend)
>   "Return global export options as a plist.
> -Optional argument BACKEND, if non-nil, is a symbol specifying
> +Optional argument BACKEND, if non-nil, is an export back-end, as
> +returned by, e.g., `org-export-create-backend'.  It specifies
> which back-end specific export options should also be read in the
> process."
>   (let (plist
>       ;; Priority is given to back-end specific options.
> -     (all (append (and backend (org-export-backend-options backend))
> +     (all (append (and backend (org-export-get-all-options backend))
>                    org-export-options-alist)))
>     (dolist (cell all plist)
>       (let ((prop (car cell)))
> @@ -2058,11 +2100,10 @@ a tree with a select tag."
> ;; back-end output.  It takes care of filtering out elements or
> ;; objects according to export options and organizing the output blank
> ;; lines and white space are preserved.  The function memoizes its
> -;; results, so it is cheap to call it within translators.
> +;; results, so it is cheap to call it within transcoders.
> ;;
> ;; It is possible to modify locally the back-end used by
> ;; `org-export-data' or even use a temporary back-end by using
> -;; `org-export-data-with-translations' and
> ;; `org-export-data-with-backend'.
> ;;
> ;; Internally, three functions handle the filtering of objects and
> @@ -2190,24 +2231,6 @@ Return transcoded string."
>            results)))
>        (plist-get info :exported-data))))))
> 
> -(defun org-export-data-with-translations (data translations info)
> -  "Convert DATA into another format using a given translation table.
> -DATA is an element, an object, a secondary string or a string.
> -TRANSLATIONS is an alist between element or object types and
> -a functions handling them.  See `org-export-define-backend' for
> -more information.  INFO is a plist used as a communication
> -channel."
> -  (org-export-data
> -   data
> -   ;; Set-up a new communication channel with TRANSLATIONS as the
> -   ;; translate table and a new hash table for memoization.
> -   (org-combine-plists
> -    info
> -    (list :translate-alist translations
> -       ;; Size of the hash table is reduced since this function
> -       ;; will probably be used on short trees.
> -       :exported-data (make-hash-table :test 'eq :size 401)))))
> -
> (defun org-export-data-with-backend (data backend info)
>   "Convert DATA into BACKEND format.
> 
> @@ -2217,9 +2240,18 @@ channel.
> 
> Unlike to `org-export-with-backend', this function will
> recursively convert DATA using BACKEND translation table."
> -  (org-export-barf-if-invalid-backend backend)
> -  (org-export-data-with-translations
> -   data (org-export-backend-translate-table backend) info))
> +  (when (symbolp backend) (setq backend (org-export-get-backend backend)))
> +  (org-export-data
> +   data
> +   ;; Set-up a new communication channel with translations defined in
> +   ;; BACKEND as the translate table and a new hash table for
> +   ;; memoization.
> +   (org-combine-plists
> +    info
> +    (list :translate-alist (org-export-get-all-transcoders backend)
> +       ;; Size of the hash table is reduced since this function
> +       ;; will probably be used on short trees.
> +       :exported-data (make-hash-table :test 'eq :size 401)))))
> 
> (defun org-export--interpret-p (blob info)
>   "Non-nil if element or object BLOB should be interpreted during export.
> @@ -2713,18 +2745,19 @@ channel, as a plist.  It must return a string or 
> nil.")
>   "Call every function in FILTERS.
> 
> Functions are called with arguments VALUE, current export
> -back-end and INFO.  A function returning a nil value will be
> -skipped.  If it returns the empty string, the process ends and
> +back-end's name and INFO.  A function returning a nil value will
> +be skipped.  If it returns the empty string, the process ends and
> VALUE is ignored.
> 
> Call is done in a LIFO fashion, to be sure that developer
> specified filters, if any, are called first."
>   (catch 'exit
> -    (dolist (filter filters value)
> -      (let ((result (funcall filter value (plist-get info :back-end) info)))
> -     (cond ((not result) value)
> -           ((equal value "") (throw 'exit nil))
> -           (t (setq value result)))))))
> +    (let ((backend-name (plist-get info :back-end)))
> +      (dolist (filter filters value)
> +     (let ((result (funcall filter value backend-name info)))
> +       (cond ((not result) value)
> +             ((equal value "") (throw 'exit nil))
> +             (t (setq value result))))))))
> 
> (defun org-export-install-filters (info)
>   "Install filters properties in communication channel.
> @@ -2755,7 +2788,7 @@ Return the updated communication channel."
>                      plist key
>                      (if (atom value) (cons value (plist-get plist key))
>                        (append value (plist-get plist key))))))))
> -       (org-export-backend-filters (plist-get info :back-end)))
> +       (org-export-get-all-filters (plist-get info :back-end)))
>     ;; Return new communication channel.
>     (org-combine-plists info plist)))
> 
> @@ -2891,6 +2924,10 @@ The function assumes BUFFER's major mode is 
> `org-mode'."
>   (backend &optional subtreep visible-only body-only ext-plist)
>   "Transcode current Org buffer into BACKEND code.
> 
> +BACKEND is either an export back-end, as returned by, e.g.,
> +`org-export-create-backend', or a symbol referring to
> +a registered back-end.
> +
> If narrowing is active in the current buffer, only transcode its
> narrowed part.
> 
> @@ -2911,6 +2948,7 @@ with external parameters overriding Org default 
> settings, but
> still inferior to file-local settings.
> 
> Return code as a string."
> +  (when (symbolp backend) (setq backend (org-export-get-backend backend)))
>   (org-export-barf-if-invalid-backend backend)
>   (save-excursion
>     (save-restriction
> @@ -2943,8 +2981,9 @@ Return code as a string."
>       ;; created, where include keywords, macros are expanded and
>       ;; code blocks are evaluated.
>       (org-export-with-buffer-copy
> -      ;; Run first hook with current back-end as argument.
> -      (run-hook-with-args 'org-export-before-processing-hook backend)
> +      ;; Run first hook with current back-end's name as argument.
> +      (run-hook-with-args 'org-export-before-processing-hook
> +                          (org-export-backend-name backend))
>        (org-export-expand-include-keyword)
>        ;; Update macro templates since #+INCLUDE keywords might have
>        ;; added some new ones.
> @@ -2954,10 +2993,11 @@ Return code as a string."
>        ;; Update radio targets since keyword inclusion might have
>        ;; added some more.
>        (org-update-radio-target-regexp)
> -      ;; Run last hook with current back-end as argument.
> +      ;; Run last hook with current back-end's name as argument.
>        (goto-char (point-min))
>        (save-excursion
> -        (run-hook-with-args 'org-export-before-parsing-hook backend))
> +        (run-hook-with-args 'org-export-before-parsing-hook
> +                            (org-export-backend-name backend)))
>        ;; Update communication channel with environment.  Also
>        ;; install user's and developer's filters.
>        (setq info
> @@ -2980,9 +3020,10 @@ Return code as a string."
>        ;; Call options filters and update export options.  We do not
>        ;; use `org-export-filter-apply-functions' here since the
>        ;; arity of such filters is different.
> -      (dolist (filter (plist-get info :filter-options))
> -        (let ((result (funcall filter info backend)))
> -          (when result (setq info result))))
> +      (let ((backend-name (org-export-backend-name backend)))
> +        (dolist (filter (plist-get info :filter-options))
> +          (let ((result (funcall filter info backend-name)))
> +            (when result (setq info result)))))
>        ;; Parse buffer and call parse-tree filter on it.
>        (setq tree
>              (org-export-filter-apply-functions
> @@ -3018,7 +3059,9 @@ Return code as a string."
>   (backend buffer &optional subtreep visible-only body-only ext-plist)
>   "Call `org-export-as' with output to a specified buffer.
> 
> -BACKEND is the back-end used for transcoding, as a symbol.
> +BACKEND is either an export back-end, as returned by, e.g.,
> +`org-export-create-backend', or a symbol referring to
> +a registered back-end.
> 
> BUFFER is the output buffer.  If it already exists, it will be
> erased first, otherwise, it will be created.
> @@ -3046,8 +3089,10 @@ to kill ring.  Return buffer."
>   (backend file &optional subtreep visible-only body-only ext-plist)
>   "Call `org-export-as' with output to a specified file.
> 
> -BACKEND is the back-end used for transcoding, as a symbol.  FILE
> -is the name of the output file, as a string.
> +BACKEND is either an export back-end, as returned by, e.g.,
> +`org-export-create-backend', or a symbol referring to
> +a registered back-end.  FILE is the name of the output file, as
> +a string.
> 
> Optional arguments SUBTREEP, VISIBLE-ONLY, BODY-ONLY and
> EXT-PLIST are similar to those used in `org-export-as', which
> @@ -3074,6 +3119,10 @@ to kill ring.  Return output file's name."
> (defun org-export-string-as (string backend &optional body-only ext-plist)
>   "Transcode STRING into BACKEND code.
> 
> +BACKEND is either an export back-end, as returned by, e.g.,
> +`org-export-create-backend', or a symbol referring to
> +a registered back-end.
> +
> When optional argument BODY-ONLY is non-nil, only return body
> code, without preamble nor postamble.
> 
> @@ -3089,7 +3138,10 @@ Return code as a string."
> 
> ;;;###autoload
> (defun org-export-replace-region-by (backend)
> -  "Replace the active region by its export to BACKEND."
> +  "Replace the active region by its export to BACKEND.
> +BACKEND is either an export back-end, as returned by, e.g.,
> +`org-export-create-backend', or a symbol referring to
> +a registered back-end."
>   (if (not (org-region-active-p))
>       (user-error "No active region to replace")
>     (let* ((beg (region-beginning))
> @@ -3103,10 +3155,10 @@ Return code as a string."
> (defun org-export-insert-default-template (&optional backend subtreep)
>   "Insert all export keywords with default values at beginning of line.
> 
> -BACKEND is a symbol representing the export back-end for which
> -specific export options should be added to the template, or
> -`default' for default template.  When it is nil, the user will be
> -prompted for a category.
> +BACKEND is a symbol referring to the name of a registered export
> +back-end, for which specific export options should be added to
> +the template, or `default' for default template.  When it is nil,
> +the user will be prompted for a category.
> 
> If SUBTREEP is non-nil, export configuration will be set up
> locally for the subtree through node properties."
> @@ -3115,17 +3167,22 @@ locally for the subtree through node properties."
>   (when (and subtreep (org-before-first-heading-p))
>     (user-error "No subtree to set export options for"))
>   (let ((node (and subtreep (save-excursion (org-back-to-heading t) (point))))
> -     (backend (or backend
> -                     (intern
> -                      (org-completing-read
> -                       "Options category: "
> -                       (cons "default"
> -                             (mapcar (lambda (b) (symbol-name (car b)))
> -                                     org-export-registered-backends))))))
> +     (backend
> +      (or backend
> +          (intern
> +           (org-completing-read
> +            "Options category: "
> +            (cons "default"
> +                  (mapcar (lambda (b)
> +                            (symbol-name (org-export-backend-name b)))
> +                          org-export--registered-backends))))))
>       options keywords)
>     ;; Populate OPTIONS and KEYWORDS.
> -    (dolist (entry (if (eq backend 'default) org-export-options-alist
> -                  (org-export-backend-options backend)))
> +    (dolist (entry (cond ((eq backend 'default) org-export-options-alist)
> +                      ((org-export-backend-p backend)
> +                       (org-export-get-all-options backend))
> +                      (t (org-export-get-all-options
> +                          (org-export-backend-name backend)))))
>       (let ((keyword (nth 1 entry))
>             (option (nth 2 entry)))
>         (cond
> @@ -3502,16 +3559,20 @@ Caption lines are separated by a white space."
> ;; back-end, it may be used as a fall-back function once all specific
> ;; cases have been treated.
> 
> -(defun org-export-with-backend (back-end data &optional contents info)
> -  "Call a transcoder from BACK-END on DATA.
> -CONTENTS, when non-nil, is the transcoded contents of DATA
> -element, as a string.  INFO, when non-nil, is the communication
> -channel used for export, as a plist.."
> -  (org-export-barf-if-invalid-backend back-end)
> +(defun org-export-with-backend (backend data &optional contents info)
> +  "Call a transcoder from BACKEND on DATA.
> +BACKEND is an export back-end, as returned by, e.g.,
> +`org-export-create-backend', or a symbol referring to
> +a registered back-end.  DATA is an Org element, object, secondary
> +string or string.  CONTENTS, when non-nil, is the transcoded
> +contents of DATA element, as a string.  INFO, when non-nil, is
> +the communication channel used for export, as a plist."
> +  (when (symbolp backend) (setq backend (org-export-get-backend backend)))
> +  (org-export-barf-if-invalid-backend backend)
>   (let ((type (org-element-type data)))
>     (if (memq type '(nil org-data)) (error "No foreign transcoder available")
>       (let ((transcoder
> -          (cdr (assq type (org-export-backend-translate-table back-end)))))
> +          (cdr (assq type (org-export-get-all-transcoders backend)))))
>       (if (functionp transcoder) (funcall transcoder data contents info)
>         (error "No foreign transcoder available"))))))
> 
> @@ -5849,43 +5910,31 @@ back to standard interface."
>         (lambda (value)
>           ;; Fontify VALUE string.
>           (org-propertize value 'face 'font-lock-variable-name-face)))
> -      ;; Prepare menu entries by extracting them from
> -      ;; `org-export-registered-backends', and sorting them by
> -      ;; access key and by ordinal, if any.
> -      (backends
> -       (sort
> -        (sort
> -         (delq nil
> -               (mapcar
> -                (lambda (b)
> -                  (let ((name (car b)))
> -                    (catch 'ignored
> -                      ;; Ignore any back-end belonging to
> -                      ;; `org-export-invisible-backends' or derived
> -                      ;; from one of them.
> -                      (dolist (ignored org-export-invisible-backends)
> -                        (when (org-export-derived-backend-p name ignored)
> -                          (throw 'ignored nil)))
> -                      (org-export-backend-menu name))))
> -                org-export-registered-backends))
> -         (lambda (a b)
> -           (let ((key-a (nth 1 a))
> -                 (key-b (nth 1 b)))
> -             (cond ((and (numberp key-a) (numberp key-b))
> -                    (< key-a key-b))
> -                   ((numberp key-b) t)))))
> -        (lambda (a b) (< (car a) (car b)))))
> +      ;; Prepare menu entries by extracting them from registered
> +      ;; back-ends and sorting them by access key and by ordinal,
> +      ;; if any.
> +      (entries
> +       (sort (sort (delq nil
> +                         (mapcar 'org-export-backend-menu
> +                                 org-export--registered-backends))
> +                   (lambda (a b)
> +                     (let ((key-a (nth 1 a))
> +                           (key-b (nth 1 b)))
> +                       (cond ((and (numberp key-a) (numberp key-b))
> +                              (< key-a key-b))
> +                             ((numberp key-b) t)))))
> +             'car-less-than-car))
>        ;; Compute a list of allowed keys based on the first key
>        ;; pressed, if any.  Some keys
>        ;; (?^B, ?^V, ?^S, ?^F, ?^A, ?&, ?# and ?q) are always
>        ;; available.
>        (allowed-keys
>         (nconc (list 2 22 19 6 1)
> -              (if (not first-key) (org-uniquify (mapcar 'car backends))
> +              (if (not first-key) (org-uniquify (mapcar 'car entries))
>                  (let (sub-menu)
> -                  (dolist (backend backends (sort (mapcar 'car sub-menu) '<))
> -                    (when (eq (car backend) first-key)
> -                      (setq sub-menu (append (nth 2 backend) sub-menu))))))
> +                  (dolist (entry entries (sort (mapcar 'car sub-menu) '<))
> +                    (when (eq (car entry) first-key)
> +                      (setq sub-menu (append (nth 2 entry) sub-menu))))))
>                (cond ((eq first-key ?P) (list ?f ?p ?x ?a))
>                      ((not first-key) (list ?P)))
>                (list ?& ?#)
> @@ -5944,7 +5993,7 @@ back to standard interface."
>                               (nth 1 sub-entry)))
>                            sub-menu "")
>                           (when (zerop (mod index 2)) "\n"))))))))
> -             backends ""))
> +             entries ""))
>            ;; Publishing menu is hard-coded.
>            (format "\n[%s] Publish
>     [%s] Current file              [%s] Current project
> @@ -5979,7 +6028,7 @@ back to standard interface."
>     ;; UI, display an intrusive help buffer.
>     (if expertp
>       (org-export--dispatch-action
> -      expert-prompt allowed-keys backends options first-key expertp)
> +      expert-prompt allowed-keys entries options first-key expertp)
>       ;; At first call, create frame layout in order to display menu.
>       (unless (get-buffer "*Org Export Dispatcher*")
>       (delete-other-windows)
> @@ -6002,15 +6051,15 @@ back to standard interface."
>         (set-window-start nil pos)))
>       (org-fit-window-to-buffer)
>       (org-export--dispatch-action
> -       standard-prompt allowed-keys backends options first-key expertp))))
> +       standard-prompt allowed-keys entries options first-key expertp))))
> 
> (defun org-export--dispatch-action
> -  (prompt allowed-keys backends options first-key expertp)
> +  (prompt allowed-keys entries options first-key expertp)
>   "Read a character from command input and act accordingly.
> 
> PROMPT is the displayed prompt, as a string.  ALLOWED-KEYS is
> a list of characters available at a given step in the process.
> -BACKENDS is a list of menu entries.  OPTIONS, FIRST-KEY and
> +ENTRIES is a list of menu entries.  OPTIONS, FIRST-KEY and
> EXPERTP are the same as defined in `org-export--dispatch-ui',
> which see.
> 
> @@ -6067,9 +6116,9 @@ options as CDR."
>        first-key expertp))
>      ;; Action selected: Send key and options back to
>      ;; `org-export-dispatch'.
> -     ((or first-key (functionp (nth 2 (assq key backends))))
> +     ((or first-key (functionp (nth 2 (assq key entries))))
>       (cons (cond
> -          ((not first-key) (nth 2 (assq key backends)))
> +          ((not first-key) (nth 2 (assq key entries)))
>            ;; Publishing actions are hard-coded.  Send a special
>            ;; signal to `org-export-dispatch'.
>            ((eq first-key ?P)
> @@ -6082,10 +6131,10 @@ options as CDR."
>            ;; path. Indeed, derived backends can share the same
>            ;; FIRST-KEY.
>            (t (catch 'found
> -               (mapc (lambda (backend)
> -                       (let ((match (assq key (nth 2 backend))))
> +               (mapc (lambda (entry)
> +                       (let ((match (assq key (nth 2 entry))))
>                           (when match (throw 'found (nth 2 match)))))
> -                     (member (assq first-key backends) backends)))))
> +                     (member (assq first-key entries) entries)))))
>           options))
>      ;; Otherwise, enter sub-menu.
>      (t (org-export--dispatch-ui options key expertp)))))
> diff --git a/testing/lisp/test-ox.el b/testing/lisp/test-ox.el
> index cbae08a..0ba20f2 100644
> --- a/testing/lisp/test-ox.el
> +++ b/testing/lisp/test-ox.el
> @@ -24,30 +24,22 @@
> (unless (featurep 'ox)
>   (signal 'missing-test-dependency "org-export"))
> 
> -(defmacro org-test-with-backend (backend &rest body)
> -  "Execute body with an export back-end defined.
> -
> -BACKEND is the name of the back-end.  BODY is the body to
> -execute.  The defined back-end simply returns parsed data as Org
> -syntax."
> -  (declare (debug (form body)) (indent 1))
> -  `(let ((org-export-registered-backends
> -       ',(list
> -          (list backend
> -                :translate-alist
> -                (let (transcode-table)
> -                  (dolist (type (append org-element-all-elements
> -                                        org-element-all-objects)
> -                                transcode-table)
> -                    (push
> -                     (cons type
> -                           (lambda (obj contents info)
> -                             (funcall
> -                              (intern (format "org-element-%s-interpreter"
> -                                              type))
> -                              obj contents)))
> -                     transcode-table)))))))
> -     (progn ,@body)))
> +(defun org-test-default-backend ()
> +  "Return a default export back-end.
> +This back-end simply returns parsed data as Org syntax."
> +  (org-export-create-backend
> +   :transcoders (let (transcode-table)
> +               (dolist (type (append org-element-all-elements
> +                                     org-element-all-objects)
> +                             transcode-table)
> +                 (push
> +                  (cons type
> +                        (lambda (obj contents info)
> +                          (funcall
> +                           (intern (format "org-element-%s-interpreter"
> +                                           type))
> +                           obj contents)))
> +                  transcode-table)))))
> 
> (defmacro org-test-with-parsed-data (data &rest body)
>   "Execute body with parsed data available.
> @@ -108,12 +100,12 @@ already filled in `info'."
>   (should
>    (equal "Yes\n"
>         (org-test-with-temp-text "#+BIND: test-ox-var value"
> -         (let ((org-export-allow-bind-keywords t)
> -               org-export-registered-backends)
> -           (org-export-define-backend 'check
> +         (let ((org-export-allow-bind-keywords t))
> +           (org-export-as
> +            (org-export-create-backend
> +             :transcoders
>               '((section . (lambda (s c i)
> -                            (if (eq test-ox-var 'value) "Yes" "No")))))
> -           (org-export-as 'check))))))
> +                            (if (eq test-ox-var 'value) "Yes" "No")))))))))))
> 
> (ert-deftest test-org-export/parse-option-keyword ()
>   "Test reading all standard #+OPTIONS: items."
> @@ -276,14 +268,14 @@ Paragraph"
>     'equal
>     (org-test-with-temp-text-in-file "Test"
>       (org-mode)
> -      (let (org-export-registered-backends)
> -     (org-export-define-backend 'test
> -       '((template . (lambda (text info)
> -                       (org-element-interpret-data
> -                        (plist-get info :title) info)))))
> -     (list (org-export-as 'test)
> -           (file-name-nondirectory
> -            (file-name-sans-extension (buffer-file-name))))))))
> +      (list (org-export-as
> +          (org-export-create-backend
> +           :transcoders
> +           '((template . (lambda (text info)
> +                           (org-element-interpret-data
> +                            (plist-get info :title) info))))))
> +         (file-name-nondirectory
> +          (file-name-sans-extension (buffer-file-name)))))))
>   ;; If no title is specified, and no file is associated to the
>   ;; buffer, use buffer's name.
>   (should
> @@ -291,36 +283,37 @@ Paragraph"
>     'equal
>     (org-test-with-temp-text "Test"
>       (org-mode)
> -      (let (org-export-registered-backends)
> -     (org-export-define-backend 'test
> -       '((template . (lambda (text info)
> -                       (org-element-interpret-data
> -                        (plist-get info :title) info)))))
> -     (list (org-export-as 'test) (buffer-name))))))
> +      (list (org-export-as
> +          (org-export-create-backend
> +           :transcoders
> +           '((template . (lambda (text info)
> +                           (org-element-interpret-data
> +                            (plist-get info :title) info))))))
> +         (buffer-name)))))
>   ;; If a title is specified, use it.
>   (should
>    (equal
>     "Title"
>     (org-test-with-temp-text-in-file "#+TITLE: Title\nTest"
>       (org-mode)
> -      (let (org-export-registered-backends)
> -     (org-export-define-backend 'test
> -       '((template . (lambda (text info)
> -                       (org-element-interpret-data
> -                        (plist-get info :title) info)))))
> -     (org-export-as 'test)))))
> +      (org-export-as
> +       (org-export-create-backend
> +     :transcoders
> +     '((template . (lambda (text info)
> +                     (org-element-interpret-data
> +                      (plist-get info :title) info)))))))))
>   ;; If an empty title is specified, do not set it.
>   (should
>    (equal
>     ""
>     (org-test-with-temp-text-in-file "#+TITLE:\nTest"
>       (org-mode)
> -      (let (org-export-registered-backends)
> -     (org-export-define-backend 'test
> -       '((template . (lambda (text info)
> -                       (org-element-interpret-data
> -                        (plist-get info :title) info)))))
> -     (org-export-as 'test))))))
> +      (org-export-as
> +       (org-export-create-backend
> +     :transcoders
> +     '((template . (lambda (text info)
> +                     (org-element-interpret-data
> +                      (plist-get info :title) info))))))))))
> 
> (ert-deftest test-org-export/handle-options ()
>   "Test if export options have an impact on output."
> @@ -328,142 +321,148 @@ Paragraph"
>   (should
>    (equal ""
>         (org-test-with-temp-text "* Head1 :noexp:"
> -         (org-test-with-backend test
> -           (org-export-as 'test nil nil nil '(:exclude-tags ("noexp")))))))
> +         (org-export-as (org-test-default-backend)
> +                        nil nil nil '(:exclude-tags ("noexp"))))))
>   ;; Test include tags for headlines and inlinetasks.
>   (should
>    (equal "* H2\n** Sub :exp:\n*** Sub Sub\n"
>         (org-test-with-temp-text "* H1\n* H2\n** Sub :exp:\n*** Sub Sub\n* H3"
>           (let ((org-tags-column 0))
> -           (org-test-with-backend test
> -             (org-export-as 'test nil nil nil '(:select-tags ("exp"))))))))
> +           (org-export-as (org-test-default-backend)
> +                          nil nil nil '(:select-tags ("exp")))))))
>   ;; Test mixing include tags and exclude tags.
> -  (org-test-with-temp-text "
> +  (should
> +   (string-match
> +    "\\* Head1[ \t]+:export:\n\\*\\* Sub-Head2\n"
> +    (org-test-with-temp-text "
> * Head1 :export:
> ** Sub-Head1 :noexport:
> ** Sub-Head2
> * Head2 :noexport:
> ** Sub-Head1 :export:"
> -    (org-test-with-backend test
> -      (should
> -       (string-match
> -     "\\* Head1[ \t]+:export:\n\\*\\* Sub-Head2\n"
> -     (org-export-as
> -      'test nil nil nil
> -      '(:select-tags ("export") :exclude-tags ("noexport")))))))
> +      (org-export-as (org-test-default-backend) nil nil nil
> +                  '(:select-tags ("export") :exclude-tags ("noexport"))))))
>   ;; Ignore tasks.
>   (should
>    (equal ""
>         (let ((org-todo-keywords '((sequence "TODO" "DONE"))))
>           (org-test-with-temp-text "* TODO Head1"
> -           (org-test-with-backend test
> -             (org-export-as 'test nil nil nil '(:with-tasks nil)))))))
> +           (org-export-as (org-test-default-backend)
> +                          nil nil nil '(:with-tasks nil))))))
>   (should
>    (equal "* TODO Head1\n"
>         (let ((org-todo-keywords '((sequence "TODO" "DONE"))))
>           (org-test-with-temp-text "* TODO Head1"
> -           (org-test-with-backend test
> -             (org-export-as 'test nil nil nil '(:with-tasks t)))))))
> +           (org-export-as (org-test-default-backend)
> +                          nil nil nil '(:with-tasks t))))))
>   ;; Archived tree.
> -  (org-test-with-temp-text "* Head1 :archive:"
> -    (let ((org-archive-tag "archive"))
> -      (org-test-with-backend test
> -     (should
> -      (equal (org-export-as 'test nil nil nil '(:with-archived-trees nil))
> -             "")))))
> -  (org-test-with-temp-text "* Head1 :archive:\nbody\n** Sub-head 2"
> -    (let ((org-archive-tag "archive"))
> -      (org-test-with-backend test
> -     (should
> -      (string-match
> -       "\\* Head1[ \t]+:archive:"
> -       (org-export-as 'test nil nil nil
> -                      '(:with-archived-trees headline)))))))
> -  (org-test-with-temp-text "* Head1 :archive:"
> -    (let ((org-archive-tag "archive"))
> -      (org-test-with-backend test
> -     (should
> -      (string-match
> -       "\\`\\* Head1[ \t]+:archive:\n\\'"
> -       (org-export-as 'test nil nil nil '(:with-archived-trees t)))))))
> +  (should
> +   (equal ""
> +       (org-test-with-temp-text "* Head1 :archive:"
> +         (let ((org-archive-tag "archive"))
> +           (org-export-as (org-test-default-backend)
> +                          nil nil nil '(:with-archived-trees nil))))))
> +  (should
> +   (string-match
> +    "\\* Head1[ \t]+:archive:"
> +    (org-test-with-temp-text "* Head1 :archive:\nbody\n** Sub-head 2"
> +      (let ((org-archive-tag "archive"))
> +     (org-export-as (org-test-default-backend) nil nil nil
> +                    '(:with-archived-trees headline))))))
> +  (should
> +   (string-match
> +    "\\`\\* Head1[ \t]+:archive:\n\\'"
> +    (org-test-with-temp-text "* Head1 :archive:"
> +      (let ((org-archive-tag "archive"))
> +     (org-export-as (org-test-default-backend)
> +                    nil nil nil '(:with-archived-trees t))))))
>   ;; Clocks.
> -  (let ((org-clock-string "CLOCK:"))
> -    (org-test-with-temp-text "CLOCK: [2012-04-29 sun. 10:45]"
> -      (org-test-with-backend test
> -     (should
> -      (equal (org-export-as 'test nil nil nil '(:with-clocks t))
> -             "CLOCK: [2012-04-29 sun. 10:45]\n"))
> -     (should
> -      (equal (org-export-as 'test nil nil nil '(:with-clocks nil)) "")))))
> +  (should
> +   (equal "CLOCK: [2012-04-29 sun. 10:45]\n"
> +       (let ((org-clock-string "CLOCK:"))
> +         (org-test-with-temp-text "CLOCK: [2012-04-29 sun. 10:45]"
> +           (org-export-as (org-test-default-backend)
> +                          nil nil nil '(:with-clocks t))))))
> +  (should
> +   (equal ""
> +       (let ((org-clock-string "CLOCK:"))
> +         (org-test-with-temp-text "CLOCK: [2012-04-29 sun. 10:45]"
> +           (org-export-as (org-test-default-backend)
> +                          nil nil nil '(:with-clocks nil))))))
>   ;; Drawers.
> -  (let ((org-drawers '("TEST")))
> -    (org-test-with-temp-text ":TEST:\ncontents\n:END:"
> -      (org-test-with-backend test
> -     (should (equal (org-export-as 'test nil nil nil '(:with-drawers nil))
> -                    ""))
> -     (should (equal (org-export-as 'test nil nil nil '(:with-drawers t))
> -                    ":TEST:\ncontents\n:END:\n")))))
> -  (let ((org-drawers '("FOO" "BAR")))
> -    (org-test-with-temp-text ":FOO:\nkeep\n:END:\n:BAR:\nremove\n:END:"
> -      (org-test-with-backend test
> -     (should
> -      (equal (org-export-as 'test nil nil nil '(:with-drawers ("FOO")))
> -             ":FOO:\nkeep\n:END:\n")))))
> -  (let ((org-drawers '("FOO" "BAR")))
> -    (org-test-with-temp-text ":FOO:\nkeep\n:END:\n:BAR:\nremove\n:END:"
> -      (org-test-with-backend test
> -     (should
> -      (equal (org-export-as 'test nil nil nil '(:with-drawers (not "BAR")))
> -             ":FOO:\nkeep\n:END:\n")))))
> +  (should
> +   (equal ""
> +       (let ((org-drawers '("TEST")))
> +         (org-test-with-temp-text ":TEST:\ncontents\n:END:"
> +           (org-export-as (org-test-default-backend)
> +                          nil nil nil '(:with-drawers nil))))))
> +  (should
> +   (equal ":TEST:\ncontents\n:END:\n"
> +       (let ((org-drawers '("TEST")))
> +         (org-test-with-temp-text ":TEST:\ncontents\n:END:"
> +           (org-export-as (org-test-default-backend)
> +                          nil nil nil '(:with-drawers t))))))
> +  (should
> +   (equal ":FOO:\nkeep\n:END:\n"
> +       (let ((org-drawers '("FOO" "BAR")))
> +         (org-test-with-temp-text ":FOO:\nkeep\n:END:\n:BAR:\nremove\n:END:"
> +           (org-export-as (org-test-default-backend)
> +                          nil nil nil '(:with-drawers ("FOO")))))))
> +  (should
> +   (equal ":FOO:\nkeep\n:END:\n"
> +       (let ((org-drawers '("FOO" "BAR")))
> +         (org-test-with-temp-text ":FOO:\nkeep\n:END:\n:BAR:\nremove\n:END:"
> +           (org-export-as (org-test-default-backend)
> +                          nil nil nil '(:with-drawers (not "BAR")))))))
>   ;; Footnotes.
>   (should
>    (equal "Footnote?"
>         (let ((org-footnote-section nil))
>           (org-test-with-temp-text "Footnote?[fn:1]\n\n[fn:1] Def"
> -           (org-test-with-backend test
> -             (org-trim
> -              (org-export-as 'test nil nil nil '(:with-footnotes nil))))))))
> +           (org-trim (org-export-as (org-test-default-backend)
> +                                    nil nil nil '(:with-footnotes nil)))))))
>   (should
>    (equal "Footnote?[fn:1]\n\n[fn:1] Def"
>         (let ((org-footnote-section nil))
>           (org-test-with-temp-text "Footnote?[fn:1]\n\n[fn:1] Def"
> -           (org-test-with-backend test
> -             (org-trim
> -              (org-export-as 'test nil nil nil '(:with-footnotes t))))))))
> +           (org-trim (org-export-as (org-test-default-backend)
> +                                    nil nil nil '(:with-footnotes t)))))))
>   ;; Inlinetasks.
>   (when (featurep 'org-inlinetask)
>     (should
>      (equal
> +      ""
>       (let ((org-inlinetask-min-level 15))
>       (org-test-with-temp-text "*************** Task"
> -       (org-test-with-backend test
> -         (org-export-as 'test nil nil nil '(:with-inlinetasks nil)))))
> -      ""))
> +       (org-export-as (org-test-default-backend)
> +                      nil nil nil '(:with-inlinetasks nil))))))
>     (should
>      (equal
> +      ""
>       (let ((org-inlinetask-min-level 15))
>       (org-test-with-temp-text
>           "*************** Task\nContents\n*************** END"
> -       (org-test-with-backend test
> -         (org-export-as 'test nil nil nil '(:with-inlinetasks nil)))))
> -      "")))
> +       (org-export-as (org-test-default-backend)
> +                      nil nil nil '(:with-inlinetasks nil)))))))
>   ;; Plannings.
> -  (let ((org-closed-string "CLOSED:"))
> -    (org-test-with-temp-text "CLOSED: [2012-04-29 sun. 10:45]"
> -      (org-test-with-backend test
> -     (should
> -      (equal (org-export-as 'test nil nil nil '(:with-planning t))
> -             "CLOSED: [2012-04-29 sun. 10:45]\n"))
> -     (should
> -      (equal (org-export-as 'test nil nil nil '(:with-planning nil))
> -             "")))))
> +  (should
> +   (equal "CLOSED: [2012-04-29 sun. 10:45]\n"
> +       (let ((org-closed-string "CLOSED:"))
> +         (org-test-with-temp-text "CLOSED: [2012-04-29 sun. 10:45]"
> +           (org-export-as (org-test-default-backend)
> +                          nil nil nil '(:with-planning t))))))
> +  (should
> +   (equal ""
> +       (let ((org-closed-string "CLOSED:"))
> +         (org-test-with-temp-text "CLOSED: [2012-04-29 sun. 10:45]"
> +           (org-export-as (org-test-default-backend)
> +                          nil nil nil '(:with-planning nil))))))
>   ;; Statistics cookies.
>   (should
>    (equal ""
>         (org-test-with-temp-text "[0/0]"
> -         (org-test-with-backend test
> -           (org-export-as
> -            'test nil nil nil '(:with-statistics-cookies nil)))))))
> +         (org-export-as (org-test-default-backend)
> +                        nil nil nil '(:with-statistics-cookies nil))))))
> 
> (ert-deftest test-org-export/with-timestamps ()
>   "Test `org-export-with-timestamps' specifications."
> @@ -472,15 +471,15 @@ Paragraph"
>    (equal
>     "[2012-04-29 sun. 10:45]<2012-04-29 sun. 10:45>\n"
>     (org-test-with-temp-text "[2012-04-29 sun. 10:45]<2012-04-29 sun. 10:45>"
> -      (org-test-with-backend test
> -     (org-export-as 'test nil nil nil '(:with-timestamps t))))))
> +      (org-export-as (org-test-default-backend)
> +                  nil nil nil '(:with-timestamps t)))))
>   ;; nil value.
>   (should
>    (equal
>     ""
>     (org-test-with-temp-text "[2012-04-29 sun. 10:45]<2012-04-29 sun. 10:45>"
> -      (org-test-with-backend test
> -     (org-export-as 'test nil nil nil '(:with-timestamps nil))))))
> +      (org-export-as (org-test-default-backend)
> +                  nil nil nil '(:with-timestamps nil)))))
>   ;; `active' value.
>   (should
>    (equal
> @@ -489,9 +488,8 @@ Paragraph"
>       "<2012-03-29 Thu>[2012-03-29 Thu]
> 
> Paragraph <2012-03-29 Thu>[2012-03-29 Thu]"
> -      (org-test-with-backend test
> -     (org-trim
> -      (org-export-as 'test nil nil nil '(:with-timestamps active)))))))
> +      (org-trim (org-export-as (org-test-default-backend)
> +                            nil nil nil '(:with-timestamps active))))))
>   ;; `inactive' value.
>   (should
>    (equal
> @@ -500,16 +498,16 @@ Paragraph <2012-03-29 Thu>[2012-03-29 Thu]"
>       "<2012-03-29 Thu>[2012-03-29 Thu]
> 
> Paragraph <2012-03-29 Thu>[2012-03-29 Thu]"
> -      (org-test-with-backend test
> -     (org-trim
> -      (org-export-as 'test nil nil nil '(:with-timestamps inactive))))))))
> +      (org-trim (org-export-as (org-test-default-backend)
> +                            nil nil nil '(:with-timestamps inactive)))))))
> 
> (ert-deftest test-org-export/comment-tree ()
>   "Test if export process ignores commented trees."
> -  (let ((org-comment-string "COMMENT"))
> -    (org-test-with-temp-text "* COMMENT Head1"
> -      (org-test-with-backend test
> -     (should (equal (org-export-as 'test) ""))))))
> +  (should
> +   (equal ""
> +       (let ((org-comment-string "COMMENT"))
> +         (org-test-with-temp-text "* COMMENT Head1"
> +           (org-export-as (org-test-default-backend)))))))
> 
> (ert-deftest test-org-export/export-scope ()
>   "Test all export scopes."
> @@ -518,22 +516,23 @@ Paragraph <2012-03-29 Thu>[2012-03-29 Thu]"
> ** Head2
> text
> *** Head3"
> -    (org-test-with-backend test
> -      ;; Subtree.
> -      (forward-line 3)
> -      (should (equal (org-export-as 'test 'subtree) "text\n*** Head3\n"))
> -      ;; Visible.
> -      (goto-char (point-min))
> -      (forward-line)
> -      (org-cycle)
> -      (should (equal (org-export-as 'test nil 'visible) "* Head1\n"))
> -      ;; Region.
> -      (goto-char (point-min))
> -      (forward-line 3)
> -      (transient-mark-mode 1)
> -      (push-mark (point) t t)
> -      (goto-char (point-at-eol))
> -      (should (equal (org-export-as 'test) "text\n"))))
> +    ;; Subtree.
> +    (forward-line 3)
> +    (should (equal (org-export-as (org-test-default-backend) 'subtree)
> +                "text\n*** Head3\n"))
> +    ;; Visible.
> +    (goto-char (point-min))
> +    (forward-line)
> +    (org-cycle)
> +    (should (equal (org-export-as (org-test-default-backend) nil 'visible)
> +                "* Head1\n"))
> +    ;; Region.
> +    (goto-char (point-min))
> +    (forward-line 3)
> +    (transient-mark-mode 1)
> +    (push-mark (point) t t)
> +    (goto-char (point-at-eol))
> +    (should (equal (org-export-as (org-test-default-backend)) "text\n")))
>   ;; Subtree with a code block calling another block outside.
>   (should
>    (equal ": 3\n"
> @@ -547,19 +546,18 @@ text
> #+BEGIN_SRC emacs-lisp
> \(+ 1 2)
> #+END_SRC"
> -         (org-test-with-backend test
> -           (forward-line 1)
> -           (org-export-as 'test 'subtree)))))
> +         (forward-line 1)
> +         (org-export-as (org-test-default-backend) 'subtree))))
>   ;; Body only.
> -  (org-test-with-temp-text "Text"
> -    (org-test-with-backend test
> -      (plist-put
> -       (cdr (assq 'test org-export-registered-backends))
> -       :translate-alist
> -       (cons (cons 'template (lambda (body info) (format "BEGIN\n%sEND" 
> body)))
> -          (org-export-backend-translate-table 'test)))
> -      (should (equal (org-export-as 'test nil nil 'body-only) "Text\n"))
> -      (should (equal (org-export-as 'test) "BEGIN\nText\nEND")))))
> +  (let ((backend (org-test-default-backend)))
> +    (setf (org-export-backend-transcoders backend)
> +       (cons '(template . (lambda (body i)
> +                            (format "BEGIN\n%sEND" body)))
> +             (org-export-backend-transcoders backend)))
> +    (org-test-with-temp-text "Text"
> +      (should (equal (org-export-as backend nil nil 'body-only)
> +                  "Text\n"))
> +      (should (equal (org-export-as backend) "BEGIN\nText\nEND")))))
> 
> (ert-deftest test-org-export/output-file-name ()
>   "Test `org-export-output-file-name' specifications."
> @@ -667,7 +665,7 @@ body\n")))
>   (should
>    (equal "#+MACRO: macro1 value\nvalue\n"
>         (org-test-with-temp-text "#+MACRO: macro1 value\n{{{macro1}}}"
> -         (org-test-with-backend test (org-export-as 'test)))))
> +         (org-export-as (org-test-default-backend)))))
>   ;; Expand specific macros.
>   (should
>    (equal "me 2012-03-29 address@hidden Title\n"
> @@ -678,7 +676,7 @@ body\n")))
> #+AUTHOR: me
> #+EMAIL: address@hidden
> {{{author}}} {{{date}}} {{{email}}} {{{title}}}"
> -         (let ((output (org-test-with-backend test (org-export-as 'test))))
> +         (let ((output (org-export-as (org-test-default-backend))))
>             (substring output (string-match ".*\n\\'" output))))))
>   ;; Expand specific macros when property contained a regular macro
>   ;; already.
> @@ -688,7 +686,7 @@ body\n")))
> #+MACRO: macro1 value
> #+TITLE: {{{macro1}}}
> {{{title}}}"
> -         (let ((output (org-test-with-backend test (org-export-as 'test))))
> +         (let ((output (org-export-as (org-test-default-backend))))
>             (substring output (string-match ".*\n\\'" output))))))
>   ;; Expand macros with templates in included files.
>   (should
> @@ -696,57 +694,65 @@ body\n")))
>         (org-test-with-temp-text
>             (format "#+INCLUDE: \"%s/examples/macro-templates.org\"
> {{{included-macro}}}" org-test-dir)
> -         (let ((output (org-test-with-backend test (org-export-as 'test))))
> +         (let ((output (org-export-as (org-test-default-backend))))
>             (substring output (string-match ".*\n\\'" output)))))))
> 
> (ert-deftest test-org-export/user-ignore-list ()
>   "Test if `:ignore-list' accepts user input."
> -  (org-test-with-backend test
> -    (flet ((skip-note-head
> -         (data backend info)
> -         ;; Ignore headlines with the word "note" in their title.
> -         (org-element-map data 'headline
> -           (lambda (headline)
> -             (when (string-match "\\<note\\>"
> -                                 (org-element-property :raw-value headline))
> -               (org-export-ignore-element headline info)))
> -           info)
> -         data))
> -      ;; Install function in parse tree filters.
> -      (let ((org-export-filter-parse-tree-functions '(skip-note-head)))
> -     (org-test-with-temp-text "* Head1\n* Head2 (note)\n"
> -       (should (equal (org-export-as 'test) "* Head1\n")))))))
> +  (let ((backend (org-test-default-backend)))
> +    (setf (org-export-backend-transcoders backend)
> +       (cons '(template . (lambda (body i)
> +                            (format "BEGIN\n%sEND" body)))
> +             (org-export-backend-transcoders backend)))
> +    (org-test-with-temp-text "Text"
> +      (should (equal (org-export-as backend nil nil 'body-only)
> +                  "Text\n"))
> +      (should (equal (org-export-as backend) "BEGIN\nText\nEND"))))
> +  (should
> +   (equal
> +    "* Head1\n"
> +    (let ((org-export-filter-parse-tree-functions
> +        '((lambda (data backend info)
> +            ;; Ignore headlines with the word "note" in their title.
> +            (org-element-map data 'headline
> +              (lambda (headline)
> +                (when (string-match "\\<note\\>"
> +                                    (org-element-property :raw-value
> +                                                          headline))
> +                  (org-export-ignore-element headline info)))
> +              info)
> +            data))))
> +      (org-test-with-temp-text "* Head1\n* Head2 (note)\n"
> +     (org-export-as (org-test-default-backend)))))))
> 
> (ert-deftest test-org-export/before-processing-hook ()
>   "Test `org-export-before-processing-hook'."
>   (should
>    (equal
>     "#+MACRO: mac val\nTest\n"
> -    (org-test-with-backend test
> -      (org-test-with-temp-text "#+MACRO: mac val\n{{{mac}}} Test"
> -     (let ((org-export-before-processing-hook
> -            '((lambda (backend)
> -                (while (re-search-forward "{{{" nil t)
> -                  (let ((object (org-element-context)))
> -                    (when (eq (org-element-type object) 'macro)
> -                      (delete-region
> -                       (org-element-property :begin object)
> -                       (org-element-property :end object)))))))))
> -       (org-export-as 'test)))))))
> +    (org-test-with-temp-text "#+MACRO: mac val\n{{{mac}}} Test"
> +      (let ((org-export-before-processing-hook
> +          '((lambda (backend)
> +              (while (re-search-forward "{{{" nil t)
> +                (let ((object (org-element-context)))
> +                  (when (eq (org-element-type object) 'macro)
> +                    (delete-region
> +                     (org-element-property :begin object)
> +                     (org-element-property :end object)))))))))
> +     (org-export-as (org-test-default-backend)))))))
> 
> (ert-deftest test-org-export/before-parsing-hook ()
>   "Test `org-export-before-parsing-hook'."
>   (should
>    (equal "Body 1\nBody 2\n"
> -       (org-test-with-backend test
> -         (org-test-with-temp-text "* Headline 1\nBody 1\n* Headline 2\nBody 
> 2"
> -           (let ((org-export-before-parsing-hook
> -                  '((lambda (backend)
> -                      (goto-char (point-min))
> -                      (while (re-search-forward org-outline-regexp-bol nil t)
> -                        (delete-region
> -                         (point-at-bol) (progn (forward-line) (point))))))))
> -             (org-export-as 'test)))))))
> +       (org-test-with-temp-text "* Headline 1\nBody 1\n* Headline 2\nBody 2"
> +         (let ((org-export-before-parsing-hook
> +                '((lambda (backend)
> +                    (goto-char (point-min))
> +                    (while (re-search-forward org-outline-regexp-bol nil t)
> +                      (delete-region
> +                       (point-at-bol) (progn (forward-line) (point))))))))
> +           (org-export-as (org-test-default-backend)))))))
> 
> 
> 
> @@ -833,37 +839,37 @@ body\n")))
>   ;; Translate table.
>   (should
>    (equal '((headline . my-headline-test))
> -       (let (org-export-registered-backends)
> +       (let (org-export--registered-backends)
>           (org-export-define-backend 'test '((headline . my-headline-test)))
> -         (org-export-backend-translate-table 'test))))
> +         (org-export-get-all-transcoders 'test))))
>   ;; Filters.
>   (should
>    (equal '((:filter-headline . my-filter))
> -       (let (org-export-registered-backends)
> +       (let (org-export--registered-backends)
>           (org-export-define-backend 'test
>             '((headline . my-headline-test))
>             :filters-alist '((:filter-headline . my-filter)))
> -         (org-export-backend-filters 'test))))
> +         (org-export-backend-filters (org-export-get-backend 'test)))))
>   ;; Options.
>   (should
>    (equal '((:prop value))
> -       (let (org-export-registered-backends)
> +       (let (org-export--registered-backends)
>           (org-export-define-backend 'test
>             '((headline . my-headline-test))
>             :options-alist '((:prop value)))
> -         (org-export-backend-options 'test))))
> +         (org-export-backend-options (org-export-get-backend 'test)))))
>   ;; Menu.
>   (should
>    (equal '(?k "Test Export" test)
> -       (let (org-export-registered-backends)
> +       (let (org-export--registered-backends)
>           (org-export-define-backend 'test
>             '((headline . my-headline-test))
>             :menu-entry '(?k "Test Export" test))
> -         (org-export-backend-menu 'test))))
> +         (org-export-backend-menu (org-export-get-backend 'test)))))
>   ;; Export Blocks.
>   (should
>    (equal '(("TEST" . org-element-export-block-parser))
> -       (let (org-export-registered-backends org-element-block-name-alist)
> +       (let (org-export--registered-backends org-element-block-name-alist)
>           (org-export-define-backend 'test
>             '((headline . my-headline-test))
>             :export-block '("test"))
> @@ -873,115 +879,218 @@ body\n")))
>   "Test `org-export-define-derived-backend' specifications."
>   ;; Error when parent back-end is not defined.
>   (should-error
> -   (let (org-export-registered-backends)
> +   (let (org-export--registered-backends)
>      (org-export-define-derived-backend 'test 'parent)))
>   ;; Append translation table to parent's.
>   (should
>    (equal '((:headline . test) (:headline . parent))
> -       (let (org-export-registered-backends)
> +       (let (org-export--registered-backends)
>           (org-export-define-backend 'parent '((:headline . parent)))
>           (org-export-define-derived-backend 'test 'parent
>             :translate-alist '((:headline . test)))
> -         (org-export-backend-translate-table 'test))))
> +         (org-export-get-all-transcoders 'test))))
>   ;; Options defined in the new back have priority over those defined
>   ;; in parent.
>   (should
>    (eq 'test
> -       (let (org-export-registered-backends)
> +       (let (org-export--registered-backends)
>        (org-export-define-backend 'parent
>          '((:headline . parent))
>          :options-alist '((:a nil nil 'parent)))
>        (org-export-define-derived-backend 'test 'parent
>          :options-alist '((:a nil nil 'test)))
> -      (plist-get (org-export--get-global-options 'test) :a)))))
> +      (plist-get (org-export--get-global-options
> +                  (org-export-get-backend 'test))
> +                 :a)))))
> 
> (ert-deftest test-org-export/derived-backend-p ()
>   "Test `org-export-derived-backend-p' specifications."
>   ;; Non-nil with direct match.
>   (should
> -   (let (org-export-registered-backends)
> +   (let (org-export--registered-backends)
>      (org-export-define-backend 'test '((headline . test)))
>      (org-export-derived-backend-p 'test 'test)))
>   (should
> -   (let (org-export-registered-backends)
> +   (let (org-export--registered-backends)
>      (org-export-define-backend 'test '((headline . test)))
>      (org-export-define-derived-backend 'test2 'test)
>      (org-export-derived-backend-p 'test2 'test2)))
>   ;; Non-nil with a direct parent.
>   (should
> -   (let (org-export-registered-backends)
> +   (let (org-export--registered-backends)
>      (org-export-define-backend 'test '((headline . test)))
>      (org-export-define-derived-backend 'test2 'test)
>      (org-export-derived-backend-p 'test2 'test)))
>   ;; Non-nil with an indirect parent.
>   (should
> -   (let (org-export-registered-backends)
> +   (let (org-export--registered-backends)
>      (org-export-define-backend 'test '((headline . test)))
>      (org-export-define-derived-backend 'test2 'test)
>      (org-export-define-derived-backend 'test3 'test2)
>      (org-export-derived-backend-p 'test3 'test)))
>   ;; Nil otherwise.
>   (should-not
> -   (let (org-export-registered-backends)
> +   (let (org-export--registered-backends)
>      (org-export-define-backend 'test '((headline . test)))
>      (org-export-define-backend 'test2 '((headline . test2)))
>      (org-export-derived-backend-p 'test2 'test)))
>   (should-not
> -   (let (org-export-registered-backends)
> +   (let (org-export--registered-backends)
>      (org-export-define-backend 'test '((headline . test)))
>      (org-export-define-backend 'test2 '((headline . test2)))
>      (org-export-define-derived-backend 'test3 'test2)
>      (org-export-derived-backend-p 'test3 'test))))
> 
> +(ert-deftest test-org-export/get-all-transcoders ()
> +  "Test `org-export-get-all-transcoders' specifications."
> +  ;; Return nil when back-end cannot be found.
> +  (should-not (org-export-get-all-transcoders nil))
> +  ;; Same as `org-export-transcoders' if no parent.
> +  (should
> +   (equal '((headline . ignore))
> +       (org-export-get-all-transcoders
> +        (org-export-create-backend
> +         :transcoders '((headline . ignore))))))
> +  ;; But inherit from all ancestors whenever possible.
> +  (should
> +   (equal '((section . ignore) (headline . ignore))
> +       (let (org-export--registered-backends)
> +         (org-export-define-backend 'b1 '((headline . ignore)))
> +         (org-export-get-all-transcoders
> +          (org-export-create-backend
> +           :parent 'b1 :transcoders '((section . ignore)))))))
> +  (should
> +   (equal '((paragraph . ignore) (section . ignore) (headline . ignore))
> +       (let (org-export--registered-backends)
> +         (org-export-define-backend 'b1 '((headline . ignore)))
> +         (org-export-define-derived-backend 'b2 'b1
> +           :translate-alist '((section . ignore)))
> +         (org-export-get-all-transcoders
> +          (org-export-create-backend
> +           :parent 'b2 :transcoders '((paragraph . ignore)))))))
> +  ;; Back-end transcoders overrule inherited ones.
> +  (should
> +   (eq 'b
> +       (let (org-export--registered-backends)
> +      (org-export-define-backend 'b1 '((headline . a)))
> +      (cdr (assq 'headline
> +                 (org-export-get-all-transcoders
> +                  (org-export-create-backend
> +                   :parent 'b1 :transcoders '((headline . b))))))))))
> +
> +(ert-deftest test-org-export/get-all-options ()
> +  "Test `org-export-get-all-options' specifications."
> +  ;; Return nil when back-end cannot be found.
> +  (should-not (org-export-get-all-options nil))
> +  ;; Same as `org-export-options' if no parent.
> +  (should
> +   (equal '((headline . ignore))
> +       (org-export-get-all-options
> +        (org-export-create-backend
> +         :options '((headline . ignore))))))
> +  ;; But inherit from all ancestors whenever possible.
> +  (should
> +   (equal '((:key2 value2) (:key1 value1))
> +       (let (org-export--registered-backends)
> +         (org-export-define-backend 'b1 nil :options-alist '((:key1 value1)))
> +         (org-export-get-all-options
> +          (org-export-create-backend
> +           :parent 'b1 :options '((:key2 value2)))))))
> +  (should
> +   (equal '((:key3 value3) (:key2 value2) (:key1 value1))
> +       (let (org-export--registered-backends)
> +         (org-export-define-backend 'b1 nil :options-alist '((:key1 value1)))
> +         (org-export-define-derived-backend 'b2 'b1
> +           :options-alist '((:key2 value2)))
> +         (org-export-get-all-options
> +          (org-export-create-backend
> +           :parent 'b2 :options '((:key3 value3)))))))
> +  ;; Back-end options overrule inherited ones.
> +  (should
> +   (eq 'b
> +       (let (org-export--registered-backends)
> +      (org-export-define-backend 'b1 nil :options-alist '((:key1 . a)))
> +      (cdr (assq :key1
> +                 (org-export-get-all-options
> +                  (org-export-create-backend
> +                   :parent 'b1 :options '((:key1 . b))))))))))
> +
> +(ert-deftest test-org-export/get-all-filters ()
> +  "Test `org-export-get-all-filters' specifications."
> +  ;; Return nil when back-end cannot be found.
> +  (should-not (org-export-get-all-filters nil))
> +  ;; Same as `org-export-filters' if no parent.
> +  (should
> +   (equal '((:filter-headline . ignore))
> +       (org-export-get-all-filters
> +        (org-export-create-backend
> +         :filters '((:filter-headline . ignore))))))
> +  ;; But inherit from all ancestors whenever possible.
> +  (should
> +   (equal '((:filter-section . ignore) (:filter-headline . ignore))
> +       (let (org-export--registered-backends)
> +         (org-export-define-backend 'b1
> +           nil :filters-alist '((:filter-headline . ignore)))
> +         (org-export-get-all-filters
> +          (org-export-create-backend
> +           :parent 'b1 :filters '((:filter-section . ignore)))))))
> +  (should
> +   (equal '((:filter-paragraph . ignore)
> +         (:filter-section . ignore)
> +         (:filter-headline . ignore))
> +       (let (org-export--registered-backends)
> +         (org-export-define-backend 'b1
> +           nil :filters-alist '((:filter-headline . ignore)))
> +         (org-export-define-derived-backend 'b2 'b1
> +           :filters-alist '((:filter-section . ignore)))
> +         (org-export-get-all-filters
> +          (org-export-create-backend
> +           :parent 'b2 :filters '((:filter-paragraph . ignore)))))))
> +  ;; Back-end filters overrule inherited ones.
> +  (should
> +   (eq 'b
> +       (let (org-export--registered-backends)
> +      (org-export-define-backend 'b1 '((:filter-headline . a)))
> +      (cdr (assq :filter-headline
> +                 (org-export-get-all-filters
> +                  (org-export-create-backend
> +                   :parent 'b1 :filters '((:filter-headline . b))))))))))
> +
> (ert-deftest test-org-export/with-backend ()
>   "Test `org-export-with-backend' definition."
>   ;; Error when calling an undefined back-end
> -  (should-error
> -   (let (org-export-registered-backends)
> -     (org-export-with-backend 'test "Test")))
> +  (should-error (org-export-with-backend nil "Test"))
>   ;; Error when called back-end doesn't have an appropriate
>   ;; transcoder.
>   (should-error
> -   (let (org-export-registered-backends)
> -     (org-export-define-backend 'test ((headline . ignore)))
> -     (org-export-with-backend 'test "Test")))
> +   (org-export-with-backend
> +    (org-export-create-backend :transcoders '((headline . ignore)))
> +    "Test"))
>   ;; Otherwise, export using correct transcoder
>   (should
>    (equal "Success"
> -       (let (org-export-registered-backends)
> +       (let (org-export--registered-backends)
>           (org-export-define-backend 'test
>             '((plain-text . (lambda (text contents info) "Failure"))))
>           (org-export-define-backend 'test2
>             '((plain-text . (lambda (text contents info) "Success"))))
>           (org-export-with-backend 'test2 "Test")))))
> 
> -(ert-deftest test-org-export/data-with-translations ()
> -  "Test `org-export-data-with-translations' specifications."
> -  (should
> -   (equal
> -    "Success!"
> -    (org-export-data-with-translations
> -     '(bold nil "Test")
> -     '((plain-text . (lambda (text info) "Success"))
> -       (bold . (lambda (bold contents info) (concat contents "!"))))
> -     '(:with-emphasize t)))))
> -
> (ert-deftest test-org-export/data-with-backend ()
>   "Test `org-export-data-with-backend' specifications."
>   ;; Error when calling an undefined back-end.
> -  (should-error
> -   (let (org-export-registered-backends)
> -     (org-export-data-with-backend 'test "Test" nil)))
> +  (should-error (org-export-data-with-backend nil "nil" nil))
>   ;; Otherwise, export data recursively, using correct back-end.
>   (should
>    (equal
>     "Success!"
> -    (let (org-export-registered-backends)
> -      (org-export-define-backend 'test
> -     '((plain-text . (lambda (text info) "Success"))
> -       (bold . (lambda (bold contents info) (concat contents "!")))))
> -      (org-export-data-with-backend
> -       '(bold nil "Test") 'test '(:with-emphasize t))))))
> +    (org-export-data-with-backend
> +     '(bold nil "Test")
> +     (org-export-create-backend
> +      :transcoders
> +      '((plain-text . (lambda (text info) "Success"))
> +     (bold . (lambda (bold contents info) (concat contents "!")))))
> +     '(:with-emphasize t)))))
> 
> 
> 
> @@ -989,28 +1098,30 @@ body\n")))
> 
> (ert-deftest test-org-export/export-snippet ()
>   "Test export snippets transcoding."
> +  ;; Standard test.
>   (org-test-with-temp-text "@@test:A@@@@t:B@@"
> -    (org-test-with-backend test
> -      (plist-put
> -       (cdr (assq 'test org-export-registered-backends))
> -       :translate-alist
> -       (cons (cons 'export-snippet
> -                (lambda (snippet contents info)
> -                  (when (eq (org-export-snippet-backend snippet) 'test)
> -                    (org-element-property :value snippet))))
> -          (org-export-backend-translate-table 'test)))
> +    (let ((backend (org-test-default-backend)))
> +      (setf (org-export-backend-name backend) 'test)
> +      (setf (org-export-backend-transcoders backend)
> +         (cons (cons 'export-snippet
> +                     (lambda (snippet contents info)
> +                       (when (eq (org-export-snippet-backend snippet) 'test)
> +                         (org-element-property :value snippet))))
> +               (org-export-backend-transcoders backend)))
>       (let ((org-export-snippet-translation-alist nil))
> -     (should (equal (org-export-as 'test) "A\n")))
> +     (should (equal (org-export-as backend) "A\n")))
>       (let ((org-export-snippet-translation-alist '(("t" . "test"))))
> -     (should (equal (org-export-as 'test) "AB\n")))))
> +     (should (equal (org-export-as backend) "AB\n")))))
>   ;; Ignored export snippets do not remove any blank.
>   (should
>    (equal "begin  end\n"
>         (org-test-with-parsed-data "begin @@test:A@@ end"
> -         (org-export-data-with-translations
> +         (org-export-data-with-backend
>            tree
> -          '((paragraph . (lambda (paragraph contents info) contents))
> -            (section . (lambda (section contents info) contents)))
> +          (org-export-create-backend
> +           :transcoders
> +           '((paragraph . (lambda (paragraph contents info) contents))
> +             (section . (lambda (section contents info) contents))))
>            info)))))
> 
> 
> @@ -1036,11 +1147,11 @@ body\n")))
>                           (car (org-element-contents def))))))))
>         info))))
>     ;; 2. Test nested footnotes order.
> -    (org-test-with-parsed-data
> -     "Text[fn:1:A[fn:2]] [fn:3].\n\n[fn:2] B [fn:3] [fn::D].\n\n[fn:3] C."
> -      (should
> -       (equal
> -     '((1 . "fn:1") (2 . "fn:2") (3 . "fn:3") (4))
> +    (should
> +     (equal
> +      '((1 . "fn:1") (2 . "fn:2") (3 . "fn:3") (4))
> +      (org-test-with-parsed-data
> +       "Text[fn:1:A[fn:2]] [fn:3].\n\n[fn:2] B [fn:3] [fn::D].\n\n[fn:3] C."
>       (org-element-map tree 'footnote-reference
>         (lambda (ref)
>           (when (org-export-footnote-first-reference-p ref info)
> @@ -1060,29 +1171,30 @@ body\n")))
>       (should
>        (= (length (org-export-collect-footnote-definitions tree info)) 2))))
>     ;; 4. Test footnotes definitions collection.
> -    (org-test-with-parsed-data "Text[fn:1:A[fn:2]] [fn:3].
> +    (should
> +     (= 4
> +     (org-test-with-parsed-data "Text[fn:1:A[fn:2]] [fn:3].
> 
> \[fn:2] B [fn:3] [fn::D].
> 
> \[fn:3] C."
> -      (should (= (length (org-export-collect-footnote-definitions tree info))
> -              4)))
> +       (length (org-export-collect-footnote-definitions tree info)))))
>     ;; 5. Test export of footnotes defined outside parsing scope.
> -    (org-test-with-temp-text "[fn:1] Out of scope
> +    (should
> +     (equal
> +      "ParagraphOut of scope\n"
> +      (org-test-with-temp-text "[fn:1] Out of scope
> * Title
> Paragraph[fn:1]"
> -      (org-test-with-backend test
> -     (plist-put
> -      (cdr (assq 'test org-export-registered-backends))
> -      :translate-alist
> -      (cons (cons 'footnote-reference
> -                  (lambda (fn contents info)
> -                    (org-element-interpret-data
> -                     (org-export-get-footnote-definition fn info))))
> -            (org-export-backend-translate-table 'test)))
> -     (forward-line)
> -     (should (equal "ParagraphOut of scope\n"
> -                    (org-export-as 'test 'subtree)))))
> +     (let ((backend (org-test-default-backend)))
> +       (setf (org-export-backend-transcoders backend)
> +             (cons (cons 'footnote-reference
> +                         (lambda (fn contents info)
> +                           (org-element-interpret-data
> +                            (org-export-get-footnote-definition fn info))))
> +                   (org-export-backend-transcoders backend)))
> +       (forward-line)
> +       (org-export-as backend 'subtree)))))
>     ;; 6. Footnotes without a definition should be provided a fallback
>     ;;    definition.
>     (should
> @@ -1378,8 +1490,8 @@ Paragraph[fn:1]"
>       ""
>       (let ((org-inlinetask-min-level 3))
>       (org-test-with-temp-text "*** Inlinetask :noexp:\nContents\n*** end"
> -       (org-test-with-backend test
> -         (org-export-as 'test nil nil nil '(:exclude-tags ("noexp"))))))))
> +       (org-export-as (org-test-default-backend)
> +                      nil nil nil '(:exclude-tags ("noexp")))))))
>     ;; Inlinetask with an include tag.
>     (should
>      (equal
> @@ -1387,16 +1499,16 @@ Paragraph[fn:1]"
>       (let ((org-inlinetask-min-level 3)
>           (org-tags-column 0))
>       (org-test-with-temp-text "* H1\n* H2\n*** Inline :exp:"
> -       (org-test-with-backend test
> -         (org-export-as 'test nil nil nil '(:select-tags ("exp"))))))))
> +       (org-export-as (org-test-default-backend)
> +                      nil nil nil '(:select-tags ("exp")))))))
>     ;; Ignore inlinetask with a TODO keyword and tasks excluded.
>     (should
>      (equal ""
>           (let ((org-todo-keywords '((sequence "TODO" "DONE")))
>                 (org-inlinetask-min-level 3))
>             (org-test-with-temp-text "*** TODO Inline"
> -             (org-test-with-backend test
> -               (org-export-as 'test nil nil nil '(:with-tasks nil)))))))))
> +             (org-export-as (org-test-default-backend)
> +                            nil nil nil '(:with-tasks nil))))))))
> 
> 
> 
> @@ -2492,41 +2604,40 @@ Another text. (ref:text)
>   "Test `inner-template' translator specifications."
>   (should
>    (equal "Success!"
> -       (let (org-export-registered-backends)
> -         (org-export-define-backend 'test
> +       (org-test-with-temp-text "* Headline"
> +         (org-export-as
> +          (org-export-create-backend
> +           :transcoders
>             '((inner-template . (lambda (contents info) "Success!"))
> -             (headline . (lambda (h c i) "Headline"))))
> -         (org-test-with-temp-text "* Headline"
> -           (org-export-as 'test)))))
> +             (headline . (lambda (h c i) "Headline"))))))))
>   ;; Inner template is applied even in a "body-only" export.
>   (should
>    (equal "Success!"
> -       (let (org-export-registered-backends)
> -         (org-export-define-backend 'test
> -           '((inner-template . (lambda (contents info) "Success!"))
> -             (headline . (lambda (h c i) "Headline"))))
> -         (org-test-with-temp-text "* Headline"
> -           (org-export-as 'test nil nil 'body-only))))))
> +       (org-test-with-temp-text "* Headline"
> +         (org-export-as
> +          (org-export-create-backend
> +           :transcoders '((inner-template . (lambda (c i) "Success!"))
> +                          (headline . (lambda (h c i) "Headline"))))
> +          nil nil 'body-only)))))
> 
> (ert-deftest test-org-export/template ()
>   "Test `template' translator specifications."
>   (should
>    (equal "Success!"
> -       (let (org-export-registered-backends)
> -         (org-export-define-backend 'test
> -           '((template . (lambda (contents info) "Success!"))
> -             (headline . (lambda (h c i) "Headline"))))
> -         (org-test-with-temp-text "* Headline"
> -           (org-export-as 'test)))))
> +       (org-test-with-temp-text "* Headline"
> +         (org-export-as
> +          (org-export-create-backend
> +           :transcoders '((template . (lambda (contents info) "Success!"))
> +                          (headline . (lambda (h c i) "Headline"))))))))
>   ;; Template is not applied in a "body-only" export.
>   (should-not
>    (equal "Success!"
> -       (let (org-export-registered-backends)
> -         (org-export-define-backend 'test
> -           '((template . (lambda (contents info) "Success!"))
> -             (headline . (lambda (h c i) "Headline"))))
> -         (org-test-with-temp-text "* Headline"
> -           (org-export-as 'test nil nil 'body-only))))))
> +       (org-test-with-temp-text "* Headline"
> +         (org-export-as
> +          (org-export-create-backend
> +           :transcoders '((template . (lambda (contents info) "Success!"))
> +                          (headline . (lambda (h c i) "Headline"))))
> +          nil nil 'body-only)))))
> 
> 
> 
> -- 
> 1.8.3.2
> 
> From 5c3b1765d219fc55edac393460128b9cd8d0d013 Mon Sep 17 00:00:00 2001
> From: Nicolas Goaziou <address@hidden>
> Date: Mon, 24 Jun 2013 20:55:24 +0200
> Subject: [PATCH 2/2] Export back-ends: Apply changes to back-end structure
> 
> * lisp/ox-html.el (org-html--format-toc-headline): Make use of
>  anonymous back-ends.
> * lisp/ox-odt.el (org-odt-footnote-reference): Make use of anonymous
>  back-ends.
> (org-odt-format-label, org-odt-toc, org-odt-format-headline--wrap):
>  Use `org-export-with-backend' instead of
>  `org-export-with-translations'.
> * contrib/lisp/ox-freemind.el (org-freemind--build-node-contents): Use
>  `org-export-with-backend' instead of `org-export-with-translations'.
> ---
> contrib/lisp/ox-freemind.el | 11 +++---
> lisp/ox-html.el             | 19 ++++++-----
> lisp/ox-odt.el              | 83 +++++++++++++++++++++++----------------------
> 3 files changed, 57 insertions(+), 56 deletions(-)
> 
> diff --git a/contrib/lisp/ox-freemind.el b/contrib/lisp/ox-freemind.el
> index 4e90eff..d31c65f 100644
> --- a/contrib/lisp/ox-freemind.el
> +++ b/contrib/lisp/ox-freemind.el
> @@ -316,12 +316,11 @@ will result in following node:
>        (element-contents (org-element-contents element))
>        (section (assoc 'section element-contents))
>        (section-contents
> -       (let* ((translations
> -               (nconc (list (cons 'section
> -                                  (lambda (section contents info)
> -                                    contents)))
> -                      (plist-get info :translate-alist))))
> -         (org-export-data-with-translations section translations info)))
> +       (let ((backend (org-export-create-backend
> +                       :parent (org-export-backend-name
> +                                (plist-get info :back-end))
> +                       :translations '(section . (lambda (e c i) c)))))
> +         (org-export-data-with-backend section backend info)))
>        (itemized-contents-p (let ((first-child-headline
>                                    (org-element-map element-contents
>                                        'headline 'identity info t)))
> diff --git a/lisp/ox-html.el b/lisp/ox-html.el
> index 9ce73c4..0c997b4 100644
> --- a/lisp/ox-html.el
> +++ b/lisp/ox-html.el
> @@ -1983,16 +1983,17 @@ INFO is a plist used as a communication channel."
>                                          headline-number "-"))))
>           ;; Body.
>           (concat section-number
> -                 (org-export-data-with-translations
> +                 (org-export-data-with-backend
>                    (org-export-get-alt-title headline info)
> -                  ;; Ignore any footnote-reference, link,
> -                  ;; radio-target and target in table of contents.
> -                  (append
> -                   '((footnote-reference . ignore)
> -                     (link . (lambda (link desc i) desc))
> -                     (radio-target . (lambda (radio desc i) desc))
> -                     (target . ignore))
> -                   (org-export-backend-translate-table 'html))
> +                  ;; Create an anonymous back-end that will ignore
> +                  ;; any footnote-reference, link, radio-target and
> +                  ;; target in table of contents.
> +                  (org-export-create-backend
> +                   :parent 'html
> +                   :transcoders '((footnote-reference . ignore)
> +                                  (link . (lambda (object c i) c))
> +                                  (radio-target . (lambda (object c i) c))
> +                                  (target . ignore)))
>                    info)
>                   (and tags "&#xa0;&#xa0;&#xa0;") (org-html--tags tags)))))
> 
> diff --git a/lisp/ox-odt.el b/lisp/ox-odt.el
> index 1cccdc6..abf88cd 100644
> --- a/lisp/ox-odt.el
> +++ b/lisp/ox-odt.el
> @@ -1152,20 +1152,19 @@ See `org-odt--build-date-styles' for implementation 
> details."
>   (let* ((title (org-export-translate "Table of Contents" :utf-8 info))
>        (headlines (org-export-collect-headlines
>                    info (and (wholenump depth) depth)))
> -      (translations (nconc (mapcar
> -                            (lambda (type)
> -                              (cons type (lambda (data contents info)
> -                                           contents)))
> -                            (list 'radio-target))
> -                           (plist-get info :translate-alist))))
> +      (backend (org-export-create-backend
> +                :parent (org-export-backend-name
> +                         (plist-get info :back-end))
> +                :transcoders (mapcar
> +                              (lambda (type) (cons type (lambda (d c i) c)))
> +                              (list 'radio-target)))))
>     (when headlines
>       (concat
>        (org-odt-begin-toc title depth)
>        (mapconcat
>       (lambda (headline)
>         (let* ((entry (org-odt-format-headline--wrap
> -                      headline translations info
> -                      'org-odt-format-toc-headline))
> +                      headline backend info 'org-odt-format-toc-headline))
>                (level (org-export-get-relative-level headline info))
>                (style (format "Contents_20_%d" level)))
>           (format "\n<text:p text:style-name=\"%s\">%s</text:p>"
> @@ -1731,18 +1730,22 @@ CONTENTS is nil.  INFO is a plist holding contextual 
> information."
>       (t
>        (let* ((raw (org-export-get-footnote-definition
>                     footnote-reference info))
> -             (translations
> -              (cons (cons 'paragraph
> -                          (lambda (p c i)
> -                            (org-odt--format-paragraph
> -                             p c "Footnote" "OrgFootnoteCenter"
> -                             "OrgFootnoteQuotations")))
> -                    (org-export-backend-translate-table 'odt)))
> -             (def (let ((def (org-trim (org-export-data-with-translations
> -                                        raw translations info))))
> -                    (if (eq (org-element-type raw) 'org-data) def
> -                      (format "\n<text:p text:style-name=\"%s\">%s</text:p>"
> -                              "Footnote" def)))))
> +             (def
> +              (let ((def (org-trim
> +                          (org-export-data-with-backend
> +                           raw
> +                           (org-export-create-backend
> +                            :parent 'odt
> +                            :transcoders
> +                            '((paragraph . (lambda (p c i)
> +                                             (org-odt--format-paragraph
> +                                              p c "Footnote"
> +                                              "OrgFootnoteCenter"
> +                                              "OrgFootnoteQuotations")))))
> +                           info))))
> +                (if (eq (org-element-type raw) 'org-data) def
> +                  (format "\n<text:p text:style-name=\"%s\">%s</text:p>"
> +                          "Footnote" def)))))
>          (funcall --format-footnote-definition n def))))))))
> 
> 
> @@ -1775,13 +1778,12 @@ CONTENTS is nil.  INFO is a plist holding contextual 
> information."
>                           "<text:span text:style-name=\"%s\">%s</text:span>"
>                           "OrgTag" tag)) tags " : "))))))
> 
> -(defun org-odt-format-headline--wrap (headline translations info
> -                                              &optional format-function
> -                                              &rest extra-keys)
> -  "Transcode a HEADLINE element from Org to ODT.
> -CONTENTS holds the contents of the headline.  INFO is a plist
> -holding contextual information."
> -  (setq translations (or translations (plist-get info :translate-alist)))
> +(defun org-odt-format-headline--wrap (headline backend info
> +                                            &optional format-function
> +                                            &rest extra-keys)
> +  "Transcode a HEADLINE element using BACKEND.
> +INFO is a plist holding contextual information."
> +  (setq backend (or backend (plist-get info :back-end)))
>   (let* ((level (+ (org-export-get-relative-level headline info)))
>        (headline-number (org-export-get-headline-number headline info))
>        (section-number (and (org-export-numbered-headline-p headline info)
> @@ -1789,13 +1791,13 @@ holding contextual information."
>                                        headline-number ".")))
>        (todo (and (plist-get info :with-todo-keywords)
>                   (let ((todo (org-element-property :todo-keyword headline)))
> -                   (and todo (org-export-data-with-translations
> -                              todo translations info)))))
> +                   (and todo
> +                        (org-export-data-with-backend todo backend info)))))
>        (todo-type (and todo (org-element-property :todo-type headline)))
>        (priority (and (plist-get info :with-priority)
>                       (org-element-property :priority headline)))
> -      (text (org-export-data-with-translations
> -             (org-element-property :title headline) translations info))
> +      (text (org-export-data-with-backend
> +             (org-element-property :title headline) backend info))
>        (tags (and (plist-get info :with-tags)
>                   (org-export-get-tags headline info)))
>        (headline-label (concat "sec-" (mapconcat 'number-to-string
> @@ -1805,7 +1807,7 @@ holding contextual information."
>                          ((functionp org-odt-format-headline-function)
>                           (function*
>                            (lambda (todo todo-type priority text tags
> -                                        &allow-other-keys)
> +                                   &allow-other-keys)
>                              (funcall org-odt-format-headline-function
>                                       todo todo-type priority text tags))))
>                          (t 'org-odt-format-headline))))
> @@ -1934,7 +1936,7 @@ holding contextual information."
>     (let ((format-function
>          (function*
>           (lambda (todo todo-type priority text tags
> -                       &key contents &allow-other-keys)
> +                  &key contents &allow-other-keys)
>             (funcall org-odt-format-inlinetask-function
>                      todo todo-type priority text tags contents)))))
>       (org-odt-format-headline--wrap
> @@ -2149,15 +2151,14 @@ SHORT-CAPTION are strings."
>        ;; will do.
>        (short-caption
>         (let ((short-caption (or short-caption caption))
> -             (translations (nconc (mapcar
> -                                   (lambda (type)
> -                                     (cons type (lambda (data contents info)
> -                                                  contents)))
> -                                   org-element-all-objects)
> -                                  (plist-get info :translate-alist))))
> +             (backend (org-export-create-backend
> +                       :parent (org-export-backend-name
> +                                (plist-get info :back-end))
> +                       :transcoders
> +                       (mapcar (lambda (type) (cons type (lambda (o c i) c)))
> +                               org-element-all-objects))))
>           (when short-caption
> -           (org-export-data-with-translations short-caption
> -                                              translations info)))))
> +           (org-export-data-with-backend short-caption backend info)))))
>     (when (or label caption)
>       (let* ((default-category
>              (case (org-element-type element)
> -- 
> 1.8.3.2
> 




reply via email to

[Prev in Thread] Current Thread [Next in Thread]