From: Thorsten Jolitz <tjolitz@gmail.com>
To: emacs-orgmode@gnu.org
Subject: Re: org-export: how to copy the parsed tree?
Date: Sat, 01 Mar 2014 11:21:37 +0100 [thread overview]
Message-ID: <878usu43ta.fsf@gmail.com> (raw)
In-Reply-To: 87r46m489o.fsf@gmail.com
Thorsten Jolitz <tjolitz@gmail.com> writes:
> Vitalie Spinu <spinuvit@gmail.com> 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
next prev parent reply other threads:[~2014-03-01 10:21 UTC|newest]
Thread overview: 8+ messages / expand[flat|nested] mbox.gz Atom feed top
2014-03-01 1:20 org-export: how to copy the parsed tree? Vitalie Spinu
2014-03-01 8:45 ` Thorsten Jolitz
2014-03-01 10:21 ` Thorsten Jolitz [this message]
2014-03-01 11:36 ` Nicolas Goaziou
2014-03-01 18:24 ` Vitalie Spinu
2014-03-01 21:02 ` Nicolas Goaziou
2014-03-01 21:21 ` Vitalie Spinu
2014-03-02 9:13 ` Nicolas Goaziou
Reply instructions:
You may reply publicly to this message via plain-text email
using any one of the following methods:
* Save the following mbox file, import it into your mail client,
and reply-to-all from there: mbox
Avoid top-posting and favor interleaved quoting:
https://en.wikipedia.org/wiki/Posting_style#Interleaved_style
List information: https://www.orgmode.org/
* Reply using the --to, --cc, and --in-reply-to
switches of git-send-email(1):
git send-email \
--in-reply-to=878usu43ta.fsf@gmail.com \
--to=tjolitz@gmail.com \
--cc=emacs-orgmode@gnu.org \
/path/to/YOUR_REPLY
https://kernel.org/pub/software/scm/git/docs/git-send-email.html
* If your mail client supports setting the In-Reply-To header
via mailto: links, try the mailto: link
Be sure your reply has a Subject: header at the top and a blank line
before the message body.
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).