やりたいこと

  • DataviewJSで取得したノートから特定の見出しを抽出して埋め込み表示を行う
    • 今回はvaultにあるすべてのノートから「## やること」を抽出する
    • ![[取得したノート#やること]] を生成するイメージ

準備

  • Obsidian Dataviewプラグインを最新版にする

    • 埋め込み表示に関する問題が0.5.65で修正されたとのこと
    • 0.5.64では動作せず
  • Dataviewを表示するノートに検索用のメタデータを追加する

    • headingValue: 抽出したい見出しの値を設定する
    • headingLevel: 抽出したい見出しのレベルを指定する
    ---
    headingValue: やること
    headingLevel: "2"
    ---
    

DataviewJSのクエリ例

クエリの例を共有します。 map の中で見出しの判定リンクの生成を行っています。

const headingPrefix = '#'.repeat(dv.current()?.headingLevel ? parseInt(dv.current().headingLevel) : 2)
const headingValue = dv.current()?.headingValue ?? ''
const headingElement = `${headingPrefix} ${headingValue}` // '## 見出し'

const source = '' // 必要に応じて検索条件を変更する
const results = dv.pages(source)
    .sort(p => p.file.path)
    .map(async p => {
        // ファイル読み込み
        const content = await dv.io.load(p.file.path)
        const lines = content.split(/\r\n|\r|\n/)
        // 特定の見出しの行があるかを確認
        if (!lines.includes(headingElement)) {
            return false
        }

        // リンクを<p>で生成
        dv.paragraph(dv.sectionLink(p.file.path, headingValue))
        // 埋め込みリンクを<span>で生成
        dv.span(dv.sectionLink(p.file.path, headingValue, true))
        return true
    })

// 抽出対象の見出しが存在しなかった場合の処理
Promise.all(results).then(results => {
    if (results.every(exist => !exist)) {
        const sourceStr = source.length > 0 ? `「${source}」` : '全件'
        dv.span(`${sourceStr}から取得したノートに「${headingElement}」は見つかりませんでした。`)
    }
})

見出しの判定

2024-05-01現在、筆者の観測範囲ではDataviewJSでノート内にある見出しの取得に関する機能を見つけられませんでした。 Redditの投稿1を参考に、取得したノートの中身を全部読み込んで「## やること」の存在を確認しています。

抽出対象の見出しが存在しなければ false を返し、存在していればリンク生成の後に true を返しています。 これは検索対象に抽出対象の見出しが存在しない場合のための値になります。

リンクの生成

特定の見出しへのリンクにはdv.sectionLinkを使用しています。 第3引数で埋め込み表示を行うかの指定ができます。 dv.sectionLinkを呼び出すだけでは何も出力されないので、出力用のdv.paragraphdv.spanを使用して表示させています。

埋め込み表示用のdv.sectionLinkでは対象のノートに飛ぶことができないため、例では通常のリンクも合わせて生成しています。 dv.paragraphdv.spanは好みで使い分けて前後の空白を管理しています。

検索対象に抽出対象の見出しが存在しない場合

見出しの判定リンクの生成の処理のみでは、抽出対象の見出しが存在しない場合にDataviewは何も出力しません。 見出しの判定で返却した配列(Promise)を確認し、すべて false であればメッセージを出力するような処理を書くことができます。 配列のすべての値を検査する目的にはArray.prototype.every()が便利ですね。

抽出対象の見出しが存在しない場合の表示例