☘️

Fast XML Parser (v4)の使い方

2022/08/11に公開

GitHub Repository

https://github.com/NaturalIntelligence/fast-xml-parser

fast-xml-parser とは

fast-xml-parser とは、XML を検証・解析・構築するための npm ライブラリです。
CLI やブラウザでも使えますが、この記事では Node.js 上での使い方を説明します。

バージョンについて

fast-xml-parser は、2022 年のはじめ頃から v4 が npm のデフォルトとしてインストールされるようになりました。バージョンアップに伴い使い方も変わっていますので、ネット上で古い記事を参照される方はご注意ください。

インストール

$ npm install fast-xml-parser

XML を読み取る

fast-xml-parser はライブラリの機能としてファイル読み込みや HTTP 通信を持っていません。そのため元ネタとなる XML がファイルの場合はファイルシステムから文字列として読み込む必要があります。Web から入手する場合も axios 等の HTTP クライアントを使ってダウンロードし、文字列として扱えるようにしてから渡します。

XMLファイルから読み取る
const fs = require("node:fs");

const xmlContent = fs.readFileSync('./sample.xml', 'utf-8')
Webから入手
const axios = require("axios");

const res = await axios.get("https://feeds.rebuild.fm/rebuildfm");
const xmlContent = res.data;

得られた XML 文字列を XMLParser を使ってパースし、JavaScript のオブジェクトに変換します。

main.js
const axios = require("axios");
const { XMLParser, XMLBuilder } = require("fast-xml-parser");

const xp = new XMLParser();

async function main() {
  const res = await axios.get("https://feeds.rebuild.fm/rebuildfm");
  const xmlContent = res.data;

  const jObj = xp.parse(xmlContent);
  console.log(jObj);
}

(async () => {
  await main();
})().catch((e) => {
  console.warn(e);
});
console
{
  '?xml': '',
  rss: {
    channel: {
      title: 'Rebuild',
      description: 'ウェブ開発、プログラミング、モバイル、ガジェットなどにフォーカスしたテクノロジー系ポッドキャストです。 #rebuildfm',
      generator: 'Jekyll',
      link: 'https://rebuild.fm',
      'atom:link': '',
      'itunes:new-feed-url': 'https://feeds.rebuild.fm/rebuildfm',

XMLParser のオプション (doc)

⚙️ ignoreDeclaration: true

XML の冒頭 1 行目には <?xml version="1.0" encoding="UTF-8"?> とった宣言文が含まれており、変換後に '?xml': '' となって現れますが、これが不要な場合に取り除くことができます。

⚙️ ignoreAttributes: false

デフォルトではタグの属性が無視されますが、これを利用したい場合に指定します。パースした場合のプロパティ名は属性名の先頭に @_ が付与されます。XML の構造を JavaScript オブジェクトまたは JSON に置き換えるとき、それが属性なのか子要素なのかを区別するためにこのような仕様になっているのだと思われます。

const options = {
  ignoreAttributes: false,
};
const xp = new XMLParser(options);

const xmlContent = `<root a="nice"><a>wow</a></root>`;
const output = xp.parse(xmlContent);
console.log(output);
//=> { root: { a: 'wow', '@_a': 'nice' } }

⚙️ cdataPropName: "__cdata"

デフォルトでは CDATA はそれを含む要素のテキストとして統合されます。これを区別して扱いたい場合はこのオプションを指定します。


XML として出力する

JavaScript のオブジェクトを渡して XML 文字列を得ます。このとき、XML 宣言文は出力されないようなので注意が必要です。

const { XMLParser, XMLBuilder } = require("fast-xml-parser");

const xb = new XMLBuilder({
  ignoreAttributes: false,
  format: true,
});

async function main() {
  const jObj = { root: { a: "wow", "@_a": "nice" } };
  const xmlContent = xb.build(jObj);
  console.log(xmlContent);
}

(async () => {
  await main();
})().catch((e) => {
  console.warn(e);
});
console
<root a="nice">
  <a>wow</a>
</root>

XMLBuilder のオプション (doc)

公式ドキュメントに詳細な説明があります。これらが必要になるほど複雑な用途で使用したことはないため、ここでは割愛いたします。


Parser と Builder の両方を使うとき

Parser と Builder は対応関係にあるため、オプションを共有して使うとよいでしょう。
また、オプションを動的に変更しないのであれば以下のようにインスタンス生成と利用箇所を分けて書くのがおすすめです。というのも、v3 では第2引数でオプション指定していたので移行の際に誤解を招くことがありました。その他、繰り返し実行の際にインスタンス生成効率を上げる意図もあります。

const { XMLParser, XMLBuilder } = require("fast-xml-parser");

const fxpOption = {
  ignoreDeclaration: true,
  ignoreAttributes: false,
  cdataPropName: "__cdata",
  format: true,
};
const xp = new XMLParser(fxpOption);
const xb = new XMLBuilder(fxpOption);

async function main() {

  const jObj = xp.parse(xmlContent);

  // ...

  const xmlContent = xb.build(jObj);
}

おわり🫡

Discussion