🚵‍♂️

【JS】XMLデータをJSONに変換(xml-js)

2023/02/25に公開

Next.jsでアプリを作成していた時、しょぼいカレンダーというサービスのAPIを使用したところ、レスポンスがJSONではなく、XMLで返ってきました。XMLデータをJSONに変換して使いたいと思い、「xml-js」というJavaScriptのライブラリを使用しました。この時のやり方や詰まった点を記載していきますので、XMLをJSONに変換したいという方の参考になれば幸いです。

作成したアプリ内容はこの記事にあります→アニメリスト検索アプリ作成してみた

結論

この記事で言いたいことを2点、先に言っておきます。

  • xml-js使ったらJSONオブジェクトが返ってくるかと思ったら、実はJSONの見た目をしたString型だったということ
  • データ型を意識する重要さ

ということです。これだけわかってもらえれば、そこまで読む意味がない記事かもしれません笑。

xml-jsのインストール

まずはアプリケーション内でxml-jsをインストールしましょう。

npm install xml-js

参考:XMLをJSONに変換できるライブラリ「xml-js」
参考:npm xml-js

APIからデータを取得

fetchの中身は今回特に気にしなくていいですが、ここでAPIを叩いて、XMLデータを取得。XMLをテキストに変換といったことが為されています。

# fetchでapiからXMLデータをresponse変数に代入
const response = await fetch(`${domain}/db.php?Command=TitleLookup&TID=${tid}`);
# XMLをテキストに変換
const dataText = await response.text();

取得できるXMLは以下リンクのような感じです。
取得できるXMLデータ例

xml-jsを使用

以下のようなコードでxml-jsライブラリを使用してdataJsonTextをconsole.logで出力してみました。すると、JSONっぽいのがコンソールに表示された!となりました。私も勘違いしたのですが、この段階ではまだJSONオブジェクトになってはいません。dataJsonTextはあくまでJSONっぽい見た目のString型であり、「オブジェクト.プロパティ」といった形でデータを取得することはできません。dataJsonTextの中身は長くなるので、参考にこの記事の最後に記載しておきます。

const convert = require('xml-js');
const dataJsonText = convert.xml2json(dataText, {compact: true, spaces: 4});

以下を実行することで、dataJsonにJSONオブジェクトを格納することができるようになりました。

const dataJson = JSON.parse(dataJsonText)

では必要なデータがある部分を取り出しましょう。

const dataComment = dataJson.TitleLookupResponse.TitleItems.TitleItem.Comment._text;

↑この書き方でデータを抽出したかったのですが、String型ではもちろんできませんよね。
dataJsonTextがString型だということに気付けずかなり時間を浪費してしまいました。

結論ここまででXMLをJSONに変換するという目標は達成されました!

どうすればdataJsonTextの型に早く気づくことができたか

オブジェクトとしてdataJsonTextを扱おうとしても、エラーが出てどうしても上手く扱えませんでした。その時にもっと早く型が違うんじゃないかと予測を立ててtypeof等を使って確認するということができればよかったかと思います。参考:typeof演算子

また、TypeScriptを使えばいいというアドバイスを知人から受けました。自分自身TypeScriptをまだ使ったことはないのですが、今後はこういった不具合の原因にすぐ気づけるようになるためにTypeScript使わなきゃと思うきっかけになりました。

補足:dataJsonTextの出力

こちらがdataJsonTextをconsole.logで表示したものです。オブジェクトっぽい見た目をしているが、これがString型だったのです。初見だと非常にわかりづらいなと感じました、、、オブジェクトの場合はChromeのコンソールに出力を表示した時に折りたためるような表示になるかと思いますが、String型では折りたたむことができません。このあたりも型が違うことを気づけるポイントだったかもしれませんね。

{
    "_declaration": {
        "_attributes": {
            "version": "1.0",
            "encoding": "UTF-8"
        }
    },
    "TitleLookupResponse": {
        "Result": {
            "Code": {
                "_text": "200"
            },
            "Message": {}
        },
        "TitleItems": {
            "TitleItem": {
                "_attributes": {
                    "id": "6556"
                },
                "TID": {
                    "_text": "6556"
                },
                "LastUpdate": {
                    "_text": "2023-02-10 01:52:50"
                },
                "Title": {
                    "_text": "お兄ちゃんはおしまい!"
                },
                "ShortTitle": {},
                "TitleYomi": {
                    "_text": "おにいちゃんはおしまい"
                },
                "TitleEN": {},
                "Comment": {
                    "_text": "*リンク\r\n-[[公式 https://onimai.jp/]]\r\n-[[Twitter https://twitter.com/onimai_anime]]\r\n-[[YouTube(TOHO animation) https://www.youtube.com/@TOHOanimation]]\r\n\r\n*メモ\r\n**Twitter・YouTube\r\n-毎週月曜ABEMA配信版に沿ったオーディオコメンタリーを配信\r\n\r\n*スタッフ\r\n:原作:ねことうふ\r\n:掲載誌:月刊ComicRex(一迅社)\r\n:監督:藤井慎吾\r\n:シリーズ構成:横手美智子\r\n:キャラクターデザイン:今村亮\r\n:美術監督:小林雅代\r\n:色彩設計:土居真紀子\r\n:メインアニメーター:みとん、松隈勇樹、内山玄基、Kay Yu\r\n:撮影監督:伏原あかね\r\n:編集:岡祐司\r\n:音響監督:吉田光平\r\n:音響効果:長谷川卓也\r\n:音響制作:ビットグルーヴプロモーション\r\n:音楽:阿知波大輔、桶狭間ありさ\r\n:音楽制作:東宝ミュージック\r\n:プロデュース:EGG FIRM\r\n:制作:スタジオバインド\r\n:製作:「おにまい」製作委員会(東宝、博報堂DYミュージック&ピクチャーズ、一迅社、AT-X、BS11、ぴあ、ポニーキャニオン、ムービック、TOKYO MX、ビットグルーヴプロモーション、EGG FIRM)\r\n\r\n*オープニングテーマ「アイデン貞貞メルトダウン」\r\n:作詞・作曲・編曲:やしきん\r\n:歌:えなこ feat.P丸様。\r\n\r\n*エンディングテーマ「ひめごと*クライシスターズ」\r\n:作詞・作曲・編曲:おぐらあすか\r\n:歌:ONIMAI SISTERES(高野麻里佳、石原夏織、金元寿子、津田美波)\r\n\r\n*キャスト\r\n:緒山まひろ:高野麻里佳\r\n:緒山みはり:石原夏織\r\n:穂月かえで:金元寿子\r\n:穂月もみじ:津田美波\r\n:桜花あさひ:優木かな\r\n:室崎みよ:日岡なつみ\r\n\r\n*次回予告イラスト\r\n:#1:松尾祐輔\r\n:#2:米山舞\r\n:#3:Kay Yu\r\n:#4:中村豊\r\n:#5:石田可奈\r\n:#6:渡辺明夫(フロントウイング)"
                },
                "Cat": {
                    "_text": "1"
                },
                "TitleFlag": {
                    "_text": "0"
                },
                "FirstYear": {
                    "_text": "2023"
                },
                "FirstMonth": {
                    "_text": "1"
                },
                "FirstEndYear": {},
                "FirstEndMonth": {},
                "FirstCh": {
                    "_text": "AT-X"
                },
                "Keywords": {},
                "UserPoint": {
                    "_text": "224"
                },
                "UserPointRank": {
                    "_text": "2"
                },
                "SubTitles": {
                    "_text": "*01*まひろとイケないカラダ\r\n*02*まひろと女の子の日\r\n*03*まひろと未知との遭遇\r\n*04*まひろとあたらしい友達\r\n*05*まひろと補導とお誘いと\r\n*06*まひろと二度目の中学生\r\n*07*まひろとロールプレイ"
                }
            }
        }
    }
}

Discussion