JavaScriptのプログラミングでサーバーを介したデータの受け渡し:Ajax通信を行う仕組みの一つにFetch APIがある。オブジェクトに最初からウェブの送受信の時間差の難点を克服するPromiseを想定して使えるのが特徴で、旧来のXMLHttpRequest APIと比べて便利に刷新された機能を有する。
しかし取得するデータがDocumentインターフェースに属さないのがちょっと使い辛い。
例えばfetch()メソッドでhtmlファイルのデータをtextで受け取ってもそこからHTMLを操作するのはUSVStringだから合わなくて全く不可能なのが厄介みたいな場合が出て来る。
Fetch APIはデータに特化して読み書きに純粋に注力するべく考案されているのか、少なくともhtmlファイルなどを一つのDOMツリーとして種々と操作するには却って旧来のXMLHttpRequestこそまだ便利だし、十分に使える状況なんだけれどもその他は不便なので、Fetch APIでも何とかならないかと望んでしまう。
DOMParserを使うとFetchのデータでもDocumentへ適合できる
幸いにも無理ではない。Fetchのデータにかぎらず、Documentへパース/解析して変換できる方法がJavaScriptにはあってDOMParserという。
使い方はとても簡単で、new演算子でコンストラクタ関数のオブジェクトを作成したらさらに引数にデータを入れたparseFromString()メソッドをかけてデータを受け取り直す。
DOMParserの使い方の見本のソースコード
var pso = new DOMParser();
var psd = pso.parseFromString(データ, "MINE type");
DOMParserのパースは三種類のファイルに対応している。
パースされるファイルとMINE typeの組み合わせ
- xmlファイル/XMLDocument
- application/xml
- text/xml
- svgファイル/SVGDocument
- image/svg+xml
- htmlファイル/HTMLDocument
- text/html
xmlファイルの二つのMINE typeはRFCの技術仕様で、2014年から「どちらでもよい、が、application/xmlを推奨」(xmlのContent-Typeはapplication/xmlか、それともtext/xml?)と定められている。
Fetchで取得したデータをDOMParserで変換する方法
送受信されるBodyに特有のデータが幾つかあるけど、しかしHTMLなどのDocumentの記述/マークアップをそのままの仕方で持っているのはtextだけで、DOMParserで変換すれば直ぐにDOMツリーとして扱えるようになる。
htmlファイルのtextをHTMLDocumentへパースするサンプル
JavaScript
var url1 ="/";
fetch (url1).then ((response1) => response1.text()).then ((text) => {
var pso1 = new DOMParser();
var psd1 = pso1.parseFromString(text, "text/html");
var txh1 = psd1.querySelector("h1#blog-title").textContent;
var bt1 = document.createElement("p");
var lk1 = document.createElement("a");
lk1.setAttribute("href", url1);
lk1.textContent = txh1;
r1.appendChild(bt1.appendChild(lk1));
lk1.insertAdjacentHTML("afterend", "(トップページ)");
});
※変数の「r1」は実行結果を表示するための親要素のIDだ。
実行結果
トップページ(ルートドメインの「/」のURL)のhtmlファイルからブログ名(h1#blog-titleの文章)を取得してリンク(aタグ)と添え書きを付けて段落(pタグ)に表示している。
Fetchのtext()メソッドで取得したtextデータのhtmlファイルなどをセレクターで分けたりして操作したい場合には事前にDOMParserでパースして相応のDocumentへ変換しながら元のファイルのDOMツリーの状態に戻さないとプログラミングを受け付けない。
htmlファイルのReadableStreamをHTMLDocumentへパースするサンプル
もう一つReadableStreamでもDocumentを使うかも知れない。Fetch APIをStreams APIと組み合わせるとデータの読み込みと書き出しを漸次的に操作することができる。このとき、必要なデータの種別がReadableStreamになって他のデータでは動作しないんだ。
ReadableStreamはByteという数字の羅列だから通常の場合でも最終的にデコード/解読して使われるけれどもhtmlファイルなどはさらにパースするとDocumentとしても扱えるようになる。
JavaScript
var url2 ="/";
const dcd = new TextDecoder();
var btc = "";
fetch (url2).then ((response2) => response2.body.getReader()).then ((reader) => {
function chunk({done, value}) {
if (done) {
return;
}
btc += dcd.decode(value);
if (/<\/h1>/.test(btc)) {
var pso2 = new DOMParser();
var psd2 = pso2.parseFromString(btc, "text/html");
var txh2 = psd2.querySelector("h1#blog-title").textContent;
var bt2 = document.createElement("p");
var lk2 = document.createElement("a");
lk2.setAttribute("href", url2);
lk2.textContent = txh2;
r2.appendChild(bt2.appendChild(lk2));
lk2.insertAdjacentHTML("afterend", "(トップページ)");
return;
}
reader.read().then(chunk);
}
reader.read().then(chunk);
});
※変数の「r2」は実行結果を表示するための親要素のIDだ。
実行結果
トップページ(ルートドメインの「/」のURL)のhtmlファイルからブログ名(h1#blog-titleの文章)を取得してリンク(aタグ)と添え書きを付けて段落(pタグ)に表示している。
FetchのBodyのbodyプロパティからgetReader()メソッドで取得したReadableStreamデータのhtmlファイルなどをセレクターで分けたりして操作したい場合、先ずはTextDecoderで文字コードをByteからデコードしなくてはならない。TextDecoderの使い方はnew演算子でコンストラクタを作成する。引数に半角引用符付きで文字コードを入力するけれども空白だと初期値の「UTF-8」へデコードされる。次いでtextデータのときと同じようにDOMParserでパースする。TextDecoderでデコードしてもReadableStreamデータはDOMStringに変わるだけなので、相応のDocumentへ変換しながら元のファイルのDOMツリーの状態に戻さないと所定のプログラミングを受け付けない。
コメント