組織モードのツリーをどのように歩くことができますか?


10

バックグラウンド

Emacsのプレゼンテーションモードを書いています。orgファイルはデータに最適であるため、入力はorgファイルにしてください。

問題

組織モードファイルを、繰り返し処理できる「スライド」データ構造のリストに変換する必要があります。これを行うには、次のorg-modeファイルのようなものを使用します。

* this is the first headline, with a title property and no contents
* this is the second headline, with contents
- dash list nested under the second headline
  - further nested
** nested headline

それを歩くことができます。私はを試しました(org-element-parse-buffer)、そしてそれは私に要素のリストを与えます、しかしそれらをさらに歩く方法を理解するのは難しいです。たとえば、呼び出し(org-element-map (org-element-parse-buffer) 'headline #'identity)3つの要素のリストを提供します。最後の1つは「ネストされた見出し」を表します。「ネストされた見出し」は「これが2番目の見出しで、内容が含まれる」の子になりたい。

XY問題の回避

私は確かに、org-modeファイルをElispデータ構造に変換する他の方法を受け入れています。私はしていないと思う ORG-輸出は、私は結果を含む新しいファイルが、データ構造で終わるしたくないので、私は反復処理することができ、私のための適切なツールです。私の素朴な方法は、「すべてのトップレベルの見出しを与えて、それらのプロパティと含まれている要素(たとえば、プレーンテキストまたはネストされたリスト-さらなる見出しかダッシュリストかに関係なく)を取得できる」のようなものです。


2
私は、第三のオプション引数信じるno-recursionのは、org-element-mapあなたが欲しいものを行う必要があります。
wvxvw 2015年

2
ファイルの下部に移動してから見出しを逆方向に検索し、すべてを取得してから、ファイルの上部に到達するまでプロセスを繰り返し続けますか?ポイントは各検索後の見出しの先頭にあるため、後方に移動します。前方に移動してから少し戻って見出しの先頭に移動するよりも効率的です。これがorg-agendaの仕組みです。つまり、org-agenda-list、org-search-view、org-tags-viewです。
弁護士、2015年

回答:


7

私は同様の問題を抱えていたので、これが役立つかもしれません-組織のエクスポートや組織の内部にはあまり詳しくありませんが、組織ファイルをツリー構造に解析するものは何も見つかりませんでした。しかし、次のようなバッファが与えられた

* 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")
弊社のサイトを使用することにより、あなたは弊社のクッキーポリシーおよびプライバシーポリシーを読み、理解したものとみなされます。
Licensed under cc by-sa 3.0 with attribution required.