emacs-orgmode
[Top][All Lists]
Advanced

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

Re: [O] org-export: how to copy the parsed tree?


From: Thorsten Jolitz
Subject: Re: [O] org-export: how to copy the parsed tree?
Date: Sat, 01 Mar 2014 11:21:37 +0100
User-agent: Gnus/5.13 (Gnus v5.13) Emacs/24.3 (gnu/linux)

Thorsten Jolitz <address@hidden> writes:

> Vitalie Spinu <address@hidden> writes:
>
>> Is there an easy way to copy org sub-tree in :filter-parse-tree?
>>
>> The structure of the parsed tree is somewhat complicated with recursive
>> references to parents in multiple places. So, copy-tree infloops.
>
> You will get a better answer most likely, but with (org-no-properties
> contents) you can get the original Org-syntax of a parse-tree element,
> e.g. applied to all sections (untested):
>
> ,----------------------------------------------------------------
> | (defun org-myexp-section (section contents info)
> |   "Transcode SECTION element into myexp syntax.
> | CONTENTS is its contents, as a string or nil. INFO is ignored."
> |   (if (and contents (stringp contents) (> (length contents) 0))
> |       (format "%S"
> |               (org-no-properties contents))
> |     ""))
> `----------------------------------------------------------------

I probably misunderstood your question. I don't know if there is an easy
way to copy a subtree, but I do know about the problems with the
recursive references, so I found a way to replace them with simple
numeric :org-elem-id and :parent-id attributes:

,--------------------------------------------
| :filters-alist '((:filter-parse-tree
|     . org-myexp-filter-parse-tree-function)
`--------------------------------------------

#+begin_src emacs-lisp
(defun org-myexp-filter-parse-tree-function (tree backend info)
  "Filter complete parsed TREE ignoring BACKEND and INFO."
   ;; optional
   (org-myexp-add-children
    (org-myexp-add-parent-ids
     (org-myexp-add-ids tree backend info)
     backend info)
    backend info))


(defun org-myexp-add-ids (tree backend info)
  "Add ':org-elem-id' property to each element of parse TREE."
  (let ((counter 1)
        (structure 1))
    (org-element-map tree myexp-default-map-types
      (lambda (--elem)
          (org-element-put-property --elem :org-elem-id counter)
          (setq counter (1+ counter))
          (and (eq (org-element-type --elem) 'plain-list)
               (org-element-put-property --elem :structure-id structure)
               (setq structure (1+ structure))))))
  tree)

(defun org-myexp--collect-children (tree)
  "Return alist with '(org-elem-id . parent-id)' pairs.
The data is collected from parse TREE."
  (let (child-lst)
    (org-element-map tree 'headline
      (lambda (--headline)
        (push (cons (org-element-property :org-elem-id --headline)
                    (org-element-property :parent-id --headline))
              child-lst)))
    child-lst))

;; optional
(defun org-myexp-add-children (tree backend info)
  "Add `:children' property to each headline in parse TREE.
Assumes that all headlines are tagged with an `:org-elem-id' property
and that the circular-list read-syntax of the `:parent' attribute
has been replaced with simple integer values (the :org-elem-id of the
elements parent)."
  (let ((pairs (org-myexp--collect-children tree)))
    (org-element-map tree 'headline
      (lambda (--elem)
        (org-element-put-property
         --elem :children
         (reverse
          (delq nil
                (mapcar
                 (lambda (--pair)
                   (and (eq (cdr --pair)
                            (org-element-property :org-elem-id --elem))
                        (car --pair)))
                 pairs)))))))
  tree)

(defun org-myexp-add-parent-ids (tree backend info)
  "Add `:parent-id' and `:parent-structure-id' to parse-tree TREE."
  (org-element-map tree myexp-all-map-types
    (lambda (--elem)
      (let ((par (org-element-property :parent --elem)))
        (and (eq (org-element-type --elem) 'item)
             (eq (org-element-type par) 'plain-list)
             (org-element-put-property
              --elem :parent-structure-id
              (org-element-property :structure-id par)))
        (org-element-put-property
         --elem :parent-id
         (if (eq (org-element-type par) 'org-data)
             0
           (org-element-property :org-elem-id par)))))
    nil nil nil 'WITH-AFFILIATED)
  tree)
#+end_src

Then in the transcode functions I build the parse-tree again without
the circular :parent attribut, but with the information contained in it
now contained in :org-elem-id and :parent-id:

#+begin_src emacs-lisp
(defun org-myexp-headline (headline contents info)
  "Transcode HEADLINE element into myexp syntax.
CONTENTS is its contents, as a string or nil.  INFO is ignored."
  (let ((props org-myexp-node-properties))
    (setq org-myexp-node-properties nil)
    (format "(headline %S %s) "
            (list
             'org-elem-id
             (org-element-property :org-elem-id headline)
             'parent-id
             (org-element-property :parent-id headline)
             [...])
            (org-no-properties contents))))
#+end_src

Not really an easy way, and I needed it for a very special purpose so it
might not fit your needs. However, this can be used to convert the
circular parse-tree to a non-circular nested list that all the usual
list processing functions can digest.

But I must say that I simply transformed all the SECTIONS to Org-syntax
(with no circular refs at all), so I ended up with only a handful
transcode functions.

Doing the above on the whole parse-tree with all its circular references
might be a tedious exercise ...

-- 
cheers,
Thorsten




reply via email to

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