emacs-orgmode@gnu.org archives
 help / color / mirror / code / Atom feed
* [RFC] Changing internal representation of back-ends to defstructs
@ 2013-07-03 20:57 Nicolas Goaziou
  2013-07-03 21:48 ` Carsten Dominik
  0 siblings, 1 reply; 15+ messages in thread
From: Nicolas Goaziou @ 2013-07-03 20:57 UTC (permalink / raw)
  To: Org Mode List

[-- Attachment #1: Type: text/plain, Size: 2706 bytes --]

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

[-- Warning: decoded text below may be mangled, UTF-8 assumed --]
[-- Attachment #2: 0001-ox-Change-back-ends-internal-representation-to-struc.patch --]
[-- Type: text/x-diff, Size: 87445 bytes --]

From 35bf951a1cd4c455f01863e128a899d36e76a76c Mon Sep 17 00:00:00 2001
From: Nicolas Goaziou <n.goaziou@gmail.com>
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."
 \f
 ;;; 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))))
 
 
 \f
@@ -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 me@here Title\n"
@@ -678,7 +676,7 @@ body\n")))
 #+AUTHOR: me
 #+EMAIL: me@here
 {{{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)))))))
 
 
 \f
@@ -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)))))
 
 
 \f
@@ -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))))))))
 
 
 \f
@@ -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)))))
 
 
 \f
-- 
1.8.3.2


[-- Warning: decoded text below may be mangled, UTF-8 assumed --]
[-- Attachment #3: 0002-Export-back-ends-Apply-changes-to-back-end-structure.patch --]
[-- Type: text/x-diff, Size: 9078 bytes --]

From 5c3b1765d219fc55edac393460128b9cd8d0d013 Mon Sep 17 00:00:00 2001
From: Nicolas Goaziou <n.goaziou@gmail.com>
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


^ permalink raw reply related	[flat|nested] 15+ messages in thread

end of thread, other threads:[~2013-07-09 16:56 UTC | newest]

Thread overview: 15+ messages (download: mbox.gz follow: Atom feed
-- links below jump to the message on this page --
2013-07-03 20:57 [RFC] Changing internal representation of back-ends to defstructs Nicolas Goaziou
2013-07-03 21:48 ` Carsten Dominik
2013-07-04 12:39   ` Nicolas Goaziou
2013-07-04 12:48     ` Bastien
2013-07-04 12:55       ` Nicolas Goaziou
2013-07-04 12:59         ` Bastien
2013-07-04 13:32           ` Nicolas Goaziou
2013-07-04 13:42     ` Nicolas Goaziou
2013-07-04 14:01       ` Bastien
2013-07-04 14:45         ` Carsten Dominik
2013-07-05 17:01       ` Eric S Fraga
2013-07-05 17:09         ` Bastien
2013-07-08 11:15           ` Eric S Fraga
2013-07-08 13:59             ` Bastien
2013-07-09 16:56               ` Eric S Fraga

Code repositories for project(s) associated with this public inbox

	https://git.savannah.gnu.org/cgit/emacs/org-mode.git

This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox;
as well as URLs for read-only IMAP folder(s) and NNTP newsgroup(s).