質問をすることでしか得られない、回答やアドバイスがある。

15分調べてもわからないことは、質問しよう!

新規登録して質問してみよう
ただいま回答率
85.35%
JavaScript

JavaScriptは、プログラミング言語のひとつです。ネットスケープコミュニケーションズで開発されました。 開発当初はLiveScriptと呼ばれていましたが、業務提携していたサン・マイクロシステムズが開発したJavaが脚光を浴びていたことから、JavaScriptと改名されました。 動きのあるWebページを作ることを目的に開発されたもので、主要なWebブラウザのほとんどに搭載されています。

Q&A

解決済

2回答

931閲覧

jsで深さがわからない子要素をjsonで簡単に構造化したい

ikeyu.tp

総合スコア6

JavaScript

JavaScriptは、プログラミング言語のひとつです。ネットスケープコミュニケーションズで開発されました。 開発当初はLiveScriptと呼ばれていましたが、業務提携していたサン・マイクロシステムズが開発したJavaが脚光を浴びていたことから、JavaScriptと改名されました。 動きのあるWebページを作ることを目的に開発されたもので、主要なWebブラウザのほとんどに搭載されています。

0グッド

1クリップ

投稿2021/11/21 08:46

閲覧ありがとうございます。

状況

contenteditableでのインライン要素指定についてこの回答内容をもとにブロックエディタを作成しています。

  • 上記のインライン要素を指定する際に

javascript

1let r = getSelection().getRangeAt(0); 2let newSpan = document.createElement('span'); 3newSpan.dataset.italic = 'true'; 4newSpan.appendChild(r.extractContents()); 5r.insertNode(newSpan);

でインライン要素をしています。

  • この方法では<span>の階層が増えてしまい,構造が複雑になってしまいます。

解決したい内容

  • 下記のようなHTMLをJavaScriptを用いてJSONで簡単に表したい。
  • 子要素の階層は無限にあり得る。(下記のHTMLでは,BoldItalicのノードにも子要素や孫要素がある可能性がある。)

html

1<div> 2 <span data-bold="true"> 3 Bold 4 </span> 5 <span data-italic="true"> 6 <span data-bold="true"> 7 BoldItalic 8 </span> 9 Italic 10 </span> 11</div>

json

1{ 2 0:{ 3 "text":"Bold",//タグ内の文字列 4 "bold":true 5 }, 6 1:{ 7 "text":"BoldItalic", 8 "bold":true,//親要素の属性も含める 9 "italic":true 10 }, 11 2:{ 12 "text":"Italic", 13 "italic":true 14 } 15}

お願いしたい解決内容

  • 子要素が有限な階層であればできるのですが,階層の数がわからず能力不足でできません。上記のHTMLをもとにJSONに変換する方法
  • DOMを操作し,下記のコードのように簡単なHTMLにする方法

html

1<div> 2 <span data-bold="true"> 3 Bold 4 </span> 5 <span data-italic="true" data-bold="true"><!--親要素のdata-italicも継承--> 6 BoldItalic 7 </span> 8 <span data-italic="true"> 9 Italic 10 </span> 11</div>

のどちらかの方法(もしくはほかの方法)のアドバイスをいただければと思います。
ご指南の程よろしくお願いします。

気になる質問をクリップする

クリップした質問は、後からいつでもMYページで確認できます。

またクリップした質問に回答があった際、通知やメールを受け取ることができます。

バッドをするには、ログインかつ

こちらの条件を満たす必要があります。

yambejp

2021/11/22 00:34

頂上のDIVは属性をひろわないのでしょうか?
ikeyu.tp

2021/11/22 00:40

それはどちらでも。DIVを親要素として子要素のspanをすべて取得してもDIVに親要素があってDIVが子要素だとしても本質的には変わらないはず(親要素をどれに設定するか)だと思うので。
yambejp

2021/11/22 01:32

親を再帰的に検索するとして、data-*の値が競合したときはどうするのでしょうか?
ikeyu.tp

2021/11/22 01:53

data-*の値が競合することはないと思いますが,競合したときは一番最後の値を採用したいと思います。
guest

回答2

0

ベストアンサー

自分だったら、何かを作ろうとしている途中で、

HTMLをJavaScriptを用いてJSONで簡単に表したい。

といった類いの汎用的な問題に当たったら、まずは、「すでに誰かがやってくれているんじゃないだろうか?」と考えて、他の人の成果に(ありがたく)乗っかることを考えます。

この質問の場合も、(ある程度信頼できて)試せるコードはないか?という目線で検索したところ、すぐに以下が見つかりました。

で、これのベストアンサーの関数、mapDOM(element, json)

javascript

1function mapDOM(element, json) { 2 var treeObject = {}; 3 4 // If string convert to document Node 5 if (typeof element === "string") { 6 if (window.DOMParser) { 7 parser = new DOMParser(); 8 docNode = parser.parseFromString(element,"text/xml"); 9 } else { // Microsoft strikes again 10 docNode = new ActiveXObject("Microsoft.XMLDOM"); 11 docNode.async = false; 12 docNode.loadXML(element); 13 } 14 element = docNode.firstChild; 15 } 16 17 //Recursively loop through DOM elements and assign properties to object 18 function treeHTML(element, object) { 19 object["type"] = element.nodeName; 20 var nodeList = element.childNodes; 21 if (nodeList != null) { 22 if (nodeList.length) { 23 object["content"] = []; 24 for (var i = 0; i < nodeList.length; i++) { 25 if (nodeList[i].nodeType == 3) { 26 object["content"].push(nodeList[i].nodeValue); 27 } else { 28 object["content"].push({}); 29 treeHTML(nodeList[i], object["content"][object["content"].length -1]); 30 } 31 } 32 } 33 } 34 if (element.attributes != null) { 35 if (element.attributes.length) { 36 object["attributes"] = {}; 37 for (var i = 0; i < element.attributes.length; i++) { 38 object["attributes"][element.attributes[i].nodeName] = element.attributes[i].nodeValue; 39 } 40 } 41 } 42 } 43 treeHTML(element, treeObject); 44 45 return (json) ? JSON.stringify(treeObject) : treeObject; 46}

を借りると、それなりに要件に近いJSONが出来るのではと思い、検証してみました。

???? tera: 370356 @codepen

どうでしょう?

エディタを作る作業を優先するのであれば、このmapDOM(element, json)をこのまま使うか、オブジェクトのプロパティだったりを微調整していく等を検討してみるのはアリかもしれません。もちろん、ちょっと寄り道して、ソースを細かく読んで理解して、これの改良版を作るのもよいかと思います。

投稿2021/11/21 09:18

編集2021/11/21 13:46
退会済みユーザー

退会済みユーザー

総合スコア0

バッドをするには、ログインかつ

こちらの条件を満たす必要があります。

ikeyu.tp

2021/11/22 01:56

ありがとうございます!! まさにやりたかったことです。自力でこの検索結果には到達できなかったので大変助かりました! ただ,このJSONをHTMLに変換することができないのでこちらもよければご指南いただければと思います。 https://teratail.com/questions/370429
guest

0

javascript

1const html=`<div> 2 <span data-bold="true"> 3 Bold 4 </span> 5 <span data-italic="true"> 6 <span data-bold="true"> 7 BoldItalic 8 </span> 9 Italic 10 </span> 11</div>`; 12const getClosest=(n,ret=[])=>(ret.push(n),(n=n.parentElement)?getClosest(n,ret):ret); 13const template = document.createElement("template"); 14template.innerHTML = html; 15const nodes=[...template.content.querySelectorAll('*')]; 16const datas=nodes.reduce((x,y)=>(x.push({ 17 text:[...y.childNodes].filter(x=>x.nodeType==3).map(x=>x.textContent.trim()).join(''), 18 ...Object.fromEntries(getClosest(y).map(x=>Object.entries(x.dataset)).flat()), 19}),x),[]); 20console.log(JSON.stringify(datas));

投稿2021/11/22 02:24

yambejp

総合スコア116724

バッドをするには、ログインかつ

こちらの条件を満たす必要があります。

あなたの回答

tips

太字

斜体

打ち消し線

見出し

引用テキストの挿入

コードの挿入

リンクの挿入

リストの挿入

番号リストの挿入

表の挿入

水平線の挿入

プレビュー

15分調べてもわからないことは
teratailで質問しよう!

ただいまの回答率
85.35%

質問をまとめることで
思考を整理して素早く解決

テンプレート機能で
簡単に質問をまとめる

質問する

関連した質問