0

Note: this is building on the solutions to putting images side-by-side in HTML and LaTeX:

orgmode image export side by side to both latex and html

Given the following org-mode document:

#+TITLE: Side-by-Side Test

* Export Configuration                                             :noexport:

  #+begin_src emacs-lisp :results output :session :exports both
    (defun my-org-backend-config (backend)
      "Set specific settings depending on which org-mode backend is used."
      (pcase backend
        ((or 'latex 'beamer)
         (setq org-export-with-tags nil)
         (setq my-remove-headlines-re (regexp-opt '(":latex:")))
         (setq my-remove-sections-re (regexp-opt '(":html:"))))
        ('html
         (setq org-export-with-tags nil)
         (setq my-remove-headlines-re (regexp-opt '(":html:")))
         (setq my-remove-sections-re (regexp-opt '(":latex:"))))
        (_
         (setq org-export-with-tags nil)
         (setq my-remove-headlines-re "")
         (setq my-remove-sections-re (regexp-opt '(":latex:" ":html:")))))
      ;; Remove sections marked by 'my-remove-sections-re'.
      (org-map-entries
       (lambda ()
         (when (save-excursion (re-search-forward my-remove-sections-re
                                                  (line-end-position) :noerror 1))
           (delete-region (point) (save-excursion (org-end-of-subtree t t))))))
      ;; Remove headlines marked by 'my-remove-headlines-re'.
      (org-map-entries
       (lambda ()
         (when (save-excursion (re-search-forward my-remove-headlines-re
                                                  (line-end-position) :noerror 1))
           (delete-region (point) (line-end-position)))))
      )
    (add-hook 'org-export-before-processing-hook #'my-org-backend-config)
  #+end_src

  #+RESULTS:


* Regular Header 1

  This is just some regular test content.

  #+NAME: a
  #+BEGIN_SRC dot :file /tmp/a.png
    digraph {
    1 -> 2;
    2 -> 3;
    }
  #+END_SRC

  #+NAME: b
  #+BEGIN_SRC dot :file /tmp/b.png
    digraph {
    1 -> 3;
    2 -> 3;
    }
  #+END_SRC

* HTML                                                                 :html:

  #+ATTR_HTML: :align center :height 300
  [[/tmp/a.png]]
  [[/tmp/b.png]]

* LaTeX                                                               :latex:

  #+BEGIN_CENTER
  #+ATTR_LATEX: :height 0.4\textwidth :center
  #+RESULTS: a
  [[file:/tmp/a.png]]
  #+ATTR_LATEX: :height 0.4\textwidth :center
  #+RESULTS: b
  [[file:/tmp/b.png]]
  #+END_CENTER


* Regular Header 2

  Testing a regular header, again.

Essentially, I want to strip out the sections marked with :html: when exporting to LaTeX and remove the headlines marked with :latex:. Vice versa for HTML-exports.

As written, this works fine for LaTeX, however I cannot remove the whole :latex: section when exporting as HTML; the headline is removed, but the content remains. I assume there's something wrong with the elisp code, but I cannot figure out exactly what it is.

(Note that this requires you to C-c C-c on the export configuration source block.)

2
  • I don't know what's wrong but I have a comment: instead of running the function on each headline and depending on the regexp to decide whether to delete or not, I think it would be better to use the match argument of org-map-entries to select the appropriate headlines: (org-map-entries (lambda () ...) (format tag)) where tag is set to either latex or html. I think that would simplify the lambdas and it also would allow for easier testing.
    – NickD
    Commented Feb 2, 2023 at 17:57
  • The bug is most probably because you are deleting the subtree which messes up org-map-entries's accounting. Do C-h v org-map-continue-from and read the Mapping API section of the manual.
    – NickD
    Commented Feb 2, 2023 at 18:24

1 Answer 1

1

Here's a fixed-up version of the code block along the lines described in my comments (i.e. 1. using the match argument of org-map-entries instead of visiting every headline and depending on a regexp to decide whether to whack it or not and 2. using org-map-continue-from to make sure that we don't skip a section after we delete one):

  #+begin_src emacs-lisp :results output :session :exports none
    (defun my-org-backend-config (backend)
      "Set specific settings depending on which org-mode backend is used."
      (pcase backend
    ((or 'latex 'beamer)
     (setq org-export-with-tags nil)
     (setq my-remove-headlines-tag "latex")
     (setq my-remove-sections-tags '("html")))
    ('html
     (setq org-export-with-tags nil)
     (setq my-remove-headlines-tag "html")
     (setq my-remove-sections-tags '("latex")))
    (_
     (setq org-export-with-tags nil)
     (setq my-remove-headlines-tag nil)
     (setq my-remove-sections-tags '("latex" "html"))))
      ;; Remove sections marked by 'my-remove-sections-re'.
    (setq match-expr (mapconcat #'identity my-remove-sections-tags "|"))
    (org-map-entries
     (lambda ()
       (let ((beg (point))
         (end (save-excursion (org-end-of-subtree t t))))
         (delete-region beg end)
         (setq org-map-continue-from beg)))
     match-expr)
    ;; Remove headlines marked by 'my-remove-headlines-re'.
    (when my-remove-headlines-tag
      (org-map-entries
       (lambda ()
         (delete-region (point) (line-end-position)))
       my-remove-headlines-tag)))
    (add-hook 'org-export-before-processing-hook #'my-org-backend-config)
  #+end_src

As mentioned in the comment, do C-h v org-map-continue-from to read the doc string of the variable and consult the Mapping API section of the manual for the important details.

BTW, the name of the hook org-export-before-processing-hook has changed in Org 9.6 to org-export-before-processing-functions. The old name is still available for backward compatibility, but will eventually disappear, so when/if you upgrade to Org 9.6, you will want to change the name in the above code.

Also BTW, although I don't think it makes any difference in this case, you might consider using a different hook: org-export-before-parsing-hook (org-export-before-parsing-functions in 9.6 and later). This hook is run after #+INCLUDE: keywords and Org mode macros have been processed (in contrast to the before-processing one, which is run before these steps), so if you are including files and you expect the latex/html processing in the code block to apply to the contents of these files, you should use this second hook.

1
  • Aah, the classical iterator invalidation issues, thanks for the thorough answer and for providing details for these hooks, I was wondering what the distinction between them was.
    – Xaldew
    Commented Feb 3, 2023 at 10:25

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Not the answer you're looking for? Browse other questions tagged or ask your own question.