[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