NodeListからJSON階層を再帰的に構築するにはどうすればよいですか?

サーワン・アフィフィ

次の入力が与えられます:

<dl>
  <dt>
    <h3>Title A</h3>
    <dl>
      <dt>
        <h3>Title A- A</h3>
        <dl>
          <dt><a href="#">Item</a></dt>
          <dt><a href="#">Item</a></dt>
        </dl>
      </dt>
      <dt><a href="#">Item</a></dt>
      <dt><a href="#">Item</a></dt>
      <dt><a href="#">Item</a></dt>
      <dt><a href="#">Item</a></dt>
      <dt>
        <h3>Title B- A</h3>
        <dl>
          <dt><a href="#">Item</a></dt>
          <dt><a href="#">Item</a></dt>
        </dl>
      </dt>
      <dt><a href="#">Item</a></dt>
    </dl>
  </dt>
</dl>

上記の入力に基づいてJSONオブジェクトを作成したいと思います。

{
  "title": "Title A",
  "children": [
    {
      "title": "Title A- A",
      "children": [
        {"title": "Item"},
        {"title": "Item"}
      ]
    },
    {"title": "Item"},
    {"title": "Item"},
    {"title": "Item"},
    {"title": "Item"},
    {
      "title": "Title B- A",
      "children": [
        {"title": "Item"},
        {"title": "Item"}
      ]
    },
    {"title": "Item"}
  ]
}

これが私がこれまでに試したことです:

function buildTree(node) {
    if (!node) return [];
    const h3 = node.querySelector('h3') || node.querySelector('a');
    let result = {
        title: h3.innerText,
        children: []
    };
    const array = [...node.querySelectorAll('dl')];
    if (array) {
        result.children = array.map(el => buildTree(el.querySelector('dt')));
    }
    return result;
}

私が得ている結果は私が期待しているものとは異なります、これが私が得ている結果です:

{
  "title": "Title A",
  "children": [
    {
      "title": "Title A",
      "children": [
        {
          "title": "Title A- A",
          "children": [
            {
              "title": "Item A- A 1",
              "children": []
            }
          ]
        },
        {
          "title": "Item A- A 1",
          "children": []
        },
        {
          "title": "Title B- A 1",
          "children": []
        }
      ]
    },
    {
      "title": "Title A- A",
      "children": [
        {
          "title": "Item A- A 1",
          "children": []
        }
      ]
    },
    {
      "title": "Item A- A 1",
      "children": []
    },
    {
      "title": "Title B- A 1",
      "children": []
    }
  ]
}

一部のデータがないようですが、何が欠けているのでしょうか。

ありがとうございました

HTMLを修正

まず、あなたが誤用していることに注意しdlます。MDNドキュメントから-

HTML<dl>要素は説明リストを表します。要素は、用語のグループ(<dt>要素を使用して指定)と説明(<dd>要素によって提供される)のリストを囲みます...

ここでは、どのような正しい使い方のだdldtddのようになります-

<dl>
  <dt>Title 1</dt>
  <dd>  
    <dl>
      <dt>Title 1.1</dt>
      <dd><a href="#">Item 1.1.1</a></dd>
      <dd><a href="#">Item 1.1.2</a></dd>
    </dl>
  </dd>
  <dd><a href="#">Item 1.2</a></dd>
  <dd><a href="#">Item 1.3</a></dd>
  <dd><a href="#">Item 1.4</a></dd>
  <dd><a href="#">Item 1.5</a></dd>
  <dd>
    <dl>
      <dt>Title 1.6</dt>    
      <dd><a href="#">Item 1.6.1</a></dd>
      <dd><a href="#">Item 1.6.2</a></dd>
    </dl>
  </dd>
  <dd><a href="#">Item 1.7</a></dd>
</dl>

出力の予想される形状と一致することに注意してください-

{
  "title": "Title 1",
  "children": [
    {
      "title": "Title 1.1",
      "children": [
        {"title": "Item 1.1.1"},
        {"title": "Item 1.1.2"}
      ]
    },
    {"title": "Item 1.2"},
    {"title": "Item 1.3"},
    {"title": "Item 1.4"},
    {"title": "Item 1.5"},
    {
      "title": "Title 1.6",
      "children": [
        {"title": "Item 1.6.1"},
        {"title": "Item 1.6.2"}
      ]
    },
    {"title": "Item 1.7"}
  ]
}

fromHtml

上記のように入力HTMLを変更する意思がない(または変更できない)場合は、Scottのすばらしい回答を参照してください。提案されたhtmlのプログラムを書くために、私はそれを2つの部分に分けます。まずfromHtml、単純な再帰形式で記述します-

function fromHtml (e)
{ switch (e?.tagName)
  { case "DL":
      return Array.from(e.childNodes, fromHtml).flat()
    case "DD":
      return [ Array.from(e.childNodes, fromHtml).flat() ]
    case "DT":
    case "A":
      return e.textContent
    default:
      return []
   }
}

fromHtml(document.querySelector('dl'))

これは私たちにこの中間フォーマットを与えます-

[
  "Title 1",
  [
    "Title 1.1",
    [ "Item 1.1.1" ],
    [ "Item 1.1.2" ]
  ],
  [ "Item 1.2" ],
  [ "Item 1.3" ],
  [ "Item 1.4" ],
  [ "Item 1.5" ],
  [
    "Title 1.6",
    [ "Item 1.6.1" ],
    [ "Item 1.6.2" ]
  ],
  [ "Item 1.7" ]
]

applyLabels

その後、必要なラベルラベルapplyLabelsを追加する別の関数を作成します-titlechildren

const applyLabels = ([ title, ...children ]) =>
  children.length
    ? { title, children: children.map(applyLabels) }
    : { title }
  
const result =
  applyLabels(fromHtml(document.querySelector('dl')))
{
  "title": "Title 1",
  "children": [
    {
      "title": "Title 1.1",
      "children": [
        {"title": "Item 1.1.1"},
        {"title": "Item 1.1.2"}
      ]
    },
    {"title": "Item 1.2"},
    {"title": "Item 1.3"},
    {"title": "Item 1.4"},
    {"title": "Item 1.5"},
    {
      "title": "Title 1.6",
      "children": [
        {"title": "Item 1.6.1"},
        {"title": "Item 1.6.2"}
      ]
    },
    {"title": "Item 1.7"}
  ]
}

出力内のすべてのノードが均一な形状になることを保証する1つの最終的な変更を提案するかもしれません{ title, children }この場合にはので、それは注目に変更する価値があるapplyLabelsの書き込みに簡単ですし、それが良い振る舞い-

const applyLabels = ([ title, ...children ]) =>
  ({ title, children: children.map(applyLabels) })

はい、これは最も深い子孫が空のchildren: []プロパティを持つことを意味しますが、特定のプロパティをnullチェックする必要がないため、データの消費がはるかに簡単になります。


デモ

以下のスニペットを展開fromHtmlしてapplyLabels、ご使用のブラウザでの結果を確認してください-

function fromHtml (e)
{ switch (e?.tagName)
  { case "DL":
      return Array.from(e.childNodes, fromHtml).flat()
    case "DD":
      return [ Array.from(e.childNodes, fromHtml).flat() ]
    case "DT":
    case "A":
      return e.textContent
    default:
      return []
   }
}

const applyLabels = ([ title, ...children ]) =>
  children.length
    ? { title, children: children.map(applyLabels) }
    : { title }
  
const result =
  applyLabels(fromHtml(document.querySelector('dl')))
  
console.log(result)
<dl>
  <dt>Title 1</dt>
  <dd>  
    <dl>
      <dt>Title 1.1</dt>
      <dd><a href="#">Item 1.1.1</a></dd>
      <dd><a href="#">Item 1.1.2</a></dd>
    </dl>
  </dd>
  <dd><a href="#">Item 1.2</a></dd>
  <dd><a href="#">Item 1.3</a></dd>
  <dd><a href="#">Item 1.4</a></dd>
  <dd><a href="#">Item 1.5</a></dd>
  <dd>
    <dl>
      <dt>Title 1.6</dt>    
      <dd><a href="#">Item 1.6.1</a></dd>
      <dd><a href="#">Item 1.6.2</a></dd>
    </dl>
  </dd>
  <dd><a href="#">Item 1.7</a></dd>
</dl>


備考

再帰とデータ変換のトピックについて何百もの回答を書きましたが、それでも私が本質的な方法で使用したのはこれが初めてだと思います.flatこのQ&Aにはユースケースがあると思いましたが、スコットのコメントは私からそれを受け取りました!domNode.childNodesは真の配列でArray.prototype.flatMapはないため、使用できないため、この回答は異なります。興味深い問題をありがとう。

この記事はインターネットから収集されたものであり、転載の際にはソースを示してください。

侵害の場合は、連絡してください[email protected]

編集
0

コメントを追加

0

関連記事

分類Dev

剣道:TreeViewで再帰的な階層を作成するにはどうすればよいですか?

分類Dev

SQL Serverで(ルートから開始して)親子階層を構築するにはどうすればよいですか?

分類Dev

knitrのグリッドを使用して段階的に階層化されたプロットを構築するにはどうすればよいですか?

分類Dev

パンダの行から階層JSONを作成するにはどうすればよいですか?

分類Dev

JSONからTableview階層を作成するにはどうすればよいですか?

分類Dev

テーブル内の階層を見つけるために Teradata 再帰クエリを実行するにはどうすればよいですか?

分類Dev

コード共有の観点から再帰下降関数を構築するにはどうすればよいですか?

分類Dev

map関数を使用して次のjsonを再構築するにはどうすればよいですか?

分類Dev

階層特性を実装するにはどうすればよいですか?

分類Dev

Azure KeyVaultで階層データ構造を作成するにはどうすればよいですか

分類Dev

RecycleViewで階層データ構造を表示するにはどうすればよいですか?

分類Dev

この階乗関数を再帰的にするにはどうすればよいですか?

分類Dev

DBpediaプロパティを使用してトピック階層を構築するにはどうすればよいですか?

分類Dev

Rubyでイベントループを構築するときに無限再帰を回避するにはどうすればよいですか?

分類Dev

js / reactjs-jsonから配列にデータを再構築するにはどうすればよいですか?

分類Dev

フラットテーブルから階層構造を抽出するにはどうすればよいですか?

分類Dev

DelphiXE2に付属のIndy10を再構築するにはどうすればよいですか?

分類Dev

再帰(階乗)を適切に呼び出すにはどうすればよいですか

分類Dev

IndexedStackの子が再構築されないようにするにはどうすればよいですか?

分類Dev

fork()を再帰的に使用するにはどうすればよいですか?

分類Dev

Gradle構成を再帰的に印刷するにはどうすればよいですか?

分類Dev

APTDを「再構築」または「修復」するにはどうすればよいですか?

分類Dev

null要素なしで配列を再構築するにはどうすればよいですか?

分類Dev

Gitでリポジトリを再構築するにはどうすればよいですか?

分類Dev

Rでテーブルを再構築するにはどうすればよいですか

分類Dev

Rでデータフレームを再構築するにはどうすればよいですか?

分類Dev

Dockerhubでイメージを毎日再構築するにはどうすればよいですか?

分類Dev

再帰を使用してカスタムコントロールを構築するにはどうすればよいですか?

分類Dev

再帰: 再帰関数から値-1を返すにはどうすればよいですか

Related 関連記事

  1. 1

    剣道:TreeViewで再帰的な階層を作成するにはどうすればよいですか?

  2. 2

    SQL Serverで(ルートから開始して)親子階層を構築するにはどうすればよいですか?

  3. 3

    knitrのグリッドを使用して段階的に階層化されたプロットを構築するにはどうすればよいですか?

  4. 4

    パンダの行から階層JSONを作成するにはどうすればよいですか?

  5. 5

    JSONからTableview階層を作成するにはどうすればよいですか?

  6. 6

    テーブル内の階層を見つけるために Teradata 再帰クエリを実行するにはどうすればよいですか?

  7. 7

    コード共有の観点から再帰下降関数を構築するにはどうすればよいですか?

  8. 8

    map関数を使用して次のjsonを再構築するにはどうすればよいですか?

  9. 9

    階層特性を実装するにはどうすればよいですか?

  10. 10

    Azure KeyVaultで階層データ構造を作成するにはどうすればよいですか

  11. 11

    RecycleViewで階層データ構造を表示するにはどうすればよいですか?

  12. 12

    この階乗関数を再帰的にするにはどうすればよいですか?

  13. 13

    DBpediaプロパティを使用してトピック階層を構築するにはどうすればよいですか?

  14. 14

    Rubyでイベントループを構築するときに無限再帰を回避するにはどうすればよいですか?

  15. 15

    js / reactjs-jsonから配列にデータを再構築するにはどうすればよいですか?

  16. 16

    フラットテーブルから階層構造を抽出するにはどうすればよいですか?

  17. 17

    DelphiXE2に付属のIndy10を再構築するにはどうすればよいですか?

  18. 18

    再帰(階乗)を適切に呼び出すにはどうすればよいですか

  19. 19

    IndexedStackの子が再構築されないようにするにはどうすればよいですか?

  20. 20

    fork()を再帰的に使用するにはどうすればよいですか?

  21. 21

    Gradle構成を再帰的に印刷するにはどうすればよいですか?

  22. 22

    APTDを「再構築」または「修復」するにはどうすればよいですか?

  23. 23

    null要素なしで配列を再構築するにはどうすればよいですか?

  24. 24

    Gitでリポジトリを再構築するにはどうすればよいですか?

  25. 25

    Rでテーブルを再構築するにはどうすればよいですか

  26. 26

    Rでデータフレームを再構築するにはどうすればよいですか?

  27. 27

    Dockerhubでイメージを毎日再構築するにはどうすればよいですか?

  28. 28

    再帰を使用してカスタムコントロールを構築するにはどうすればよいですか?

  29. 29

    再帰: 再帰関数から値-1を返すにはどうすればよいですか

ホットタグ

アーカイブ