У мене була подібна проблема, тому, можливо, це допоможе - я не дуже знайомий із експортом org чи внутрішнім органом, але я не зміг знайти нічого, що б розібрало файл org із структурою дерева. Але дано буфер типу
* england
** london
** bristol
* france
це дасть тобі
(org-get-header-tree) => ("england" ("london" "bristol") "france")
і може включати й іншу інформацію з дерева.
Отже, з урахуванням плоского списку рівнів нам потрібно створити дерево, наприклад (1 1 2 3 1) => (1 1 (2 (3)) 1). Я не зміг знайти функцію, яка б це зробила, і так написав після багаточисленних малюнків мінусних комірок - я впевнений, що є кращий спосіб зробити це, але це працює. Функція unflatten
займає плоский список і пару функцій для отримання потрібної інформації зі списку та рівнів елементів та створює структуру дерева.
У org-get-header-list
можна додати додаткову інформацію ви хочете отримати з кожного пункту з викликами org-element-property
, а потім в org-get-header-tree
вас можете включати в себе функцію для вилучення інформації зі списку.
Окрім цього, це не включає обробку списків тире, але, можливо, воно може бути адаптоване для обробки також без особливих проблем ...
(defun unflatten (xs &optional fn-value fn-level)
"Unflatten a list XS into a tree, e.g. (1 2 3 1) => (1 (2 (3)) 1).
FN-VALUE specifies how to extract the values from each element, which
are included in the output tree, FN-LEVEL tells how to extract the
level of each element. By default these are the `identity' function so
it will work on a list of numbers."
(let* ((level 1)
(tree (cons nil nil))
(start tree)
(stack nil)
(fn-value (or fn-value #'identity))
(fn-level (or fn-level #'identity)))
(dolist (x xs)
(let ((x-value (funcall fn-value x))
(x-level (funcall fn-level x)))
(cond ((> x-level level)
(setcdr tree (cons (cons x-value nil) nil))
(setq tree (cdr tree))
(push tree stack)
(setq tree (car tree))
(setq level x-level))
((= x-level level)
(setcdr tree (cons x-value nil))
(setq tree (cdr tree)))
((< x-level level)
(while (< x-level level)
(setq tree (pop stack))
(setq level (- level 1)))
(setcdr tree (cons x-value nil))
(setq tree (cdr tree))
(setq level x-level)))))
(cdr start)))
; eg (unflatten '(1 2 3 2 3 4)) => '(1 (2 (3) 2 (3 (4))))
(defun org-get-header-list (&optional buffer)
"Get the headers of an org buffer as a flat list of headers and levels.
Buffer will default to the current buffer."
(interactive)
(with-current-buffer (or buffer (current-buffer))
(let ((tree (org-element-parse-buffer 'headline)))
(org-element-map
tree
'headline
(lambda (el) (list
(org-element-property :raw-value el) ; get header title without tags etc
(org-element-property :level el) ; get depth
;; >> could add other properties here
))))))
; eg (org-get-header-list) => (("pok" 1) ("lkm" 1) (("cedar" 2) ("yr" 2)) ("kjn" 1))
(defun org-get-header-tree (&optional buffer)
"Get the headers of the given org buffer as a tree."
(interactive)
(let* ((headers (org-get-header-list buffer))
(header-tree (unflatten headers
(lambda (hl) (car hl)) ; extract information to include in tree
(lambda (hl) (cadr hl))))) ; extract item level
header-tree))
; eg (org-get-header-tree) => ("pok" "lkm" ("cedar" "yr") "kjn")
no-recursion
вorg-element-map
повинен робити те , що ви хочете.