まだプログラマーですが何か?

プログラマーネタ中心。たまに作成したウェブサービス関連の話も https://twitter.com/dotnsf

タグ:xml

このお盆休みの期間を使って、久しぶりに XSL を再勉強しました。10年くらい前の以前に使っていたころと比べて事情も変わっていたようで、リスキリングという意味でもいい機会だったと思っています。改めて「そもそも XSL とは?」から「なんで XSL をやり直そうと思ったのか」という背景も含め、まとめておきます。実はこの背景部分が少々複雑で、眺めの導入説明になっている点をご了承ください。


【HTML と CSS の関係】
XSL のブログエントリでなんで HTML と CSS ? と感じる人もいると思いますが、実はこれが上述の背景部分に絡んできます。 ウェブのデザインをしたことがある人はわかっていることだと思いますが、ウェブページって、
・表示するデータを HTML で
・その見栄えは CSS で
定義することになっています。極端な言い方をすると HTML 内には見栄えに関連する要素を入れずに(HTML5 以降では見栄えに関する要素は排除される方向です)、見た目はすべて CSS で、というやり方。これはこれでメリット・デメリットある気がしますが、役割分担としてはシンプルで悪くないと感じています。

ただ、自分はこの考え方に少し違和感があります。「見栄えを CSS で」という点はいいのですが、「表示するデータを HTML で」という部分は現実と少し違っているように感じてしまうのでした。

例えばこんな HTML があったとします:
<html>
<head>
<title>成績表</title>
</head>
<body>
<h1>成績表</h1>
<table id="mytable">
<thead>
<tr><th>名前</th><th>国語</th><th>数学</th></tr>
</thead>
<tbody>
<tr><td>佐藤</td><td>50</td><td>90</td></tr>
<tr><td>鈴木</td><td>70</td><td>60</td></tr>
<tr><td>田中</td><td>80</td><td>40</td></tr>
</tbody>
</table>
</body>
</html>

一見なんの変哲もない、<h1> の見出しと成績表が定義された HTML です。これらの見出しや表部分、細かくは全体のフォントや背景色なども含めて具体的にどのような見栄えになるのかは別途 CSS で定義する、というものです。 ここで私が「表示するデータは HTML で定義」していることについて違和感を感じるのは「<title> と <h1> の両方で "成績表" が定義されていること」です。

これは HTML 的にはブラウザウィンドウのタイトル部分(<title>)と、ブラウザ内に表示されるウェブページとしての見出し部分(<h1>)なので別々に定義する必要があるものです(別々に定義しようと思えばできる、という点ではその通り)。一方で「データとして」考えるとどちらも「見出し」のデータであって、「別々に定義するつもりがないのであれば、データとしては1つ」が正しいものです。後者の考え方でウェブページを作ろうとすると、「データを定義するはずの HTML 内で <title> と <h1> の2か所で同じ内容を(2重に)定義している」とも感じます。これはもちろん HTML の仕様ともかかわる問題ではあるのですが、その HTML の仕様のせいでデータを2重管理する必要が生じてしまっているのでした。 

2重管理しないといけないものが「表示するデータを定義するもの」・・・これが私の感じた違和感でした。本来「表示データ」は2重、3重に定義せず正規化されているべきものであって、その内容を表示ページの内容に従って HTML に配置しなおして(ここで2重化されるのは理解できる)、最後に CSS で HTML の見栄えを定義する、という考え方がしっくりくるのでした。 要するに「HTML が表示データの定義」と呼ぶことに抵抗を感じていて、「表示データをウェブページの配置に沿って変換した結果が HTML」と考えるとすっきり理解しやすいのでした:
(表示データの定義(の XML 例))
<?xml version="1.0" encoding="Shift_JIS"?>
<成績表>
  <見出し>成績表</見出し>
  <結果 名前="佐藤" 国語="50" 数学="90"/>
  <結果 名前="鈴木" 国語="70" 数学="60"/>
  <結果 名前="田中" 国語="80" 数学="40"/>    
</成績表>

  ↓(変換)

(表示ウェブページの HTML) <html> <head> <title>成績表</title> </head> <body> <h1>成績表</h1> <table id="mytable"> <thead> <tr><th>名前</th><th>国語</th><th>数学</th></tr> </thead> <tbody> <tr><td>佐藤</td><td>50</td><td>90</td></tr> <tr><td>鈴木</td><td>70</td><td>60</td></tr> <tr><td>田中</td><td>80</td><td>40</td></tr> </tbody> </table> </body> </html>

(※この後 msxsl.exe というツールを使う関係でわざと XML に encoding="Shift_JIS" 指定を加えています。msxsl.exe を使わない場合は encoding 指定なしで(UTF-8 で)構いません)


【XSL とは】
XSL(eXtensible Stylesheet Language) は上述の「表示データをウェブページの配置に沿って変換した結果が HTML」の「変換ルール」に関わるものです。そして実際の変換処理そのものは XSLT(XSL Transform) と呼びます。

具体的に XML と XSL を用意して、XSLT を行ってみます。まず以下のような2つのテキストファイル data.xml と data.xsl を用意します(いずれもシフト JIS エンコードで保存してください):

(data.xml)
<?xml version="1.0" encoding="Shift_JIS"?>
<成績表>
  <見出し>成績表</見出し>
  <結果 名前="佐藤" 国語="50" 数学="90"/>
  <結果 名前="鈴木" 国語="70" 数学="60"/>
  <結果 名前="田中" 国語="80" 数学="40"/>    
</成績表>


(data.xsl)
<?xml version="1.0" encoding="Shift_JIS"?>
<xsl:stylesheet xmlns:xsl="http://www.w3.org/1999/XSL/Transform" version="1.0">
<xsl:output method="html" encoding="Shift_JIS"/>
<xsl:template match="/">
<html>
<head>
<title><xsl:value-of select="成績表/見出し" /></title>
</head>
<body>
<h1><xsl:value-of select="成績表/見出し" /></h1>
<table id="mytable">
<thead>
<tr><th>名前</th><th>国語</th><th>数学</th></tr>
</thead>
<tbody>
<xsl:for-each select="成績表/結果">
<tr>
  <td><xsl:value-of select="@名前" /></td>
  <td><xsl:value-of select="@国語" /></td>
  <td><xsl:value-of select="@数学" /></td>
</tr>
</xsl:for-each>
</tbody>
</table>
</body>
</html>
</xsl:template>
</xsl:stylesheet>



【参照】
XSLTの使い方・入門チュートリアル


data.xml が表示データの定義ファイルで、data.xsl が data.xml を HTML に変換する際の変換ルールを定義しています。<xsl:template match="/"> と </xsl:template> の間で HTML が定義されていて、<xsl:value-of> と <xsl:for-each> を使って表示データ(data.xml)のテキスト値や属性値を HTML に変換しています。

XML と XSL を使って HTML に変換(= XSL Transform)する方法はいくつかありますが、比較的簡単なマイクロソフト製コマンドラインツール msxsl.exe を使った例を紹介します、、が、このツールは便利ではあるのですが、かなり古いものらしく、マイクロソフトのサイトには存在しておらず、インターネットアーカイブ上でしか見つけることができませんでした。というわけでこちらからダウンロードしてください:
http://web.archive.org/web/20140812045521/http://www.microsoft.com/en-us/download/details.aspx?id=21714


ダウンロードできたら Windows 上でコマンドプロンプトを開き、data.xml , data.xsl の存在するフォルダに移動します。そして msxsl.exe にパスを通すか、data.xml, data.xsl と同じフォルダに msxsl.exe をコピーしてください。

準備ができたら以下を実行します:
> msxsl.exe data.xml data.xsl

msxsl.exe は2つのパラメータを指定して XSLT 処理を実行します。最初のパラメータが XML ファイルのパス、2つ目のパラメータが XSL ファイルのパスです。正しく実行できた場合は XSLT の実行結果が画面上に表示されます:
2023082001

※このコマンドプロンプト画面ではシフト JIS でないと文字化けを起こしてしまいます。その理由もあって data.xml と data.xsl をシフト JIS で作ったという背景があるのでした。

個人的には XSLT 処理をプログラミング内で行うこともあるのですが、そこでうまくいかないケースに遭遇した場合、この msxsl.exe を使うとエラー発生時の内容や箇所をエラーメッセージとして表示してくれるので、主にデバッグ目的で今でもよく使っています。


この XSL(T) を使うことで、
・表示するデータは XML で、
・XML を XSL を使って変換した HTML を使って、
・HTML の見栄えは CSS で、
それぞれ役割分担して定義する、ということが可能になります。例えばデータベースから取り出した直後のデータは XML に近い形をしていることが多いので、そこから HTML を生成する際に XSL を使い、細かな見栄えは別途 CSS で定義する、という役割分担が、自分の理解の上でも腹落ちしやすいと考えています。


【ノーツのデータ構造に似ている】
ここまでに紹介してきた XML と XSL の関係というのが、HCL ノーツ/ドミノでいうところの「文書(document)」と「フォーム(form)」の関係に似ていると思っています。ノーツではデータそのものは文書として格納されていて、その見栄えは適用されるフォームによって定義されています。同じ文書でも適用さえるフォームによって見栄えが変わる点も含めて似ているのですが、加えてノーツのデータは DXL(Domino XML Language) という特殊な XML フォーマットでインポート/エクスポートできる機能があるので、XML/XSL との相性も悪くなかったりします。

まあ現実のノーツデータはそこまで単純ではありません。ノーツにはサブフォームや共有フィールドといった設計の再利用の仕組みがあったり、HTML とは異なる独特なリッチテキスト編集/保存機能があったり、細かな所では XSL のテンプレート名称に使ってよい文字とノーツのフォーム/サブフォーム名に使ってよい文字に違いがあったりして、単純に XML/XSL 対応ができるわけではなかったりします。

とはいえ、それでもノーツのデータをノーツ外で取り扱う(これ自体がすごくハードルの高いことだったりします)ことを目指そうとすると、 DXL にエクスポートした上で XML/XSL の仕組みをベースにすることでノーツ外でも取り扱いできるようにするための近道のようには感じています。どこまで実現できるかわからないのですが、個人的にそんなツールの開発を始めていて、いずれどこかで紹介できればと思っています。




 

(以下 2023/05/15 追記)
このブログエントリで紹介している DXL Import 機能は正しく動くようになりました。記録として残しておきますが、現状は問題なく動作します。
(以上 2023/05/15 追記)


自作ツール dxl.vbs を紹介する目的で先日こんなブログエントリを書きました:
ノーツデータベースの設計変更履歴を git で管理する

このツール(dxl_export.vbs)は HCL Notes のデータベースをテキスト(XML)化することで、本来はバイナリデータであるデータベースファイルの設計変更履歴(ちょっとカスタマイズするとデータも含めた変更履歴)を git で管理できるようにする、というものです。テキストデータになっていれば変更差分の履歴や、変更一回ごとに限らず任意の2つのタイミングでの変更差分を比較する、といったことも(git の機能として)可能になる、というものでした。

実はこの dxl.vbs にはもう1つ dxl_import.vbs というツールがあります。Export と Import ということで、なんとなく機能の想像がつくかもしれませんが「XML 化されたデータから Notes データベースを復元する」ためのものです。git で変更履歴を管理しつつ、どこかのタイミングで使っていた設計状態に git checkout して、その状態を作成した時のノーツデータベースを復元する、というためのものです。が、残念ながら現時点ではこちらは期待通りに動きません。その点に関する解説ブログエントリとして記載します。

もともとこのツールは LotusScript および Java の API として用意されている DXL Import/Export の機能を使って実装しています。ツールそのものは VBS で、いわゆる ActiveX/COM を使って NotesSession オブジェクトを生成し、そこからこれらの機能を呼び出すことで Export で XML 化し、Import で復元を実装しています。この Import 部分がどうも正しく動いていないように見えるのでした。

少し補足をすると、DXL Export を実行すると指定されたデータベースが XML 化されます。実はここにも一点問題があって、「データに日本語が含まれている場合、XML には encoding 指定のない(つまり UTF-8 )データが出力されるが、実際にはシフト JIS の日本語データが含まれる」というものです。この時点で XML データとしての不整合が生じてしまっています。そのため本ツール(dxl_export.vbs)では、この XML データを書きだす前に強制的に encoding="Shift_JIS" を追加してから出力することで不整合を回避しています。

で、改めて dxl_import.vbs ですが、現状ではこのツールを実行することでノーツデータベースファイル(.nsf ファイル)を(日本語文字列含めて)復元することまではできています(※)。が、この復元結果をノーツクライアントから開こうとするとこのようなエラーが発生してしまって正しく開くことができないのでした:
20230508

↑左のアイコンがある方が元のデータベースで、これを dxl_export してから dxl_import したものが右のアイコンがない方。アイコンは復元できていないが、(日本語の)データベースタイトルは復元できている。でも開くことはできない。

※厳密には dxl_import.vbs 実行時に以下のようなエラーが発生しています。エラーにはなるけど .nsf ファイルは出力されている、という状況です:
2023051402


なお、この復元された(?)ノーツファイルを Domino Designer で開くと、フォームなどの設計要素が空になっています。という意味ではやはり DXL Import に失敗しているとみるべきなのだと思っています:
2023051401


XML の encoding 設定を勝手に書き換えたのがよくなかったのか、、と思ってやり直してみても結果は同じ。というわけで DXL Import がおかしいのか、あるいはその前の DXL Export の時点で何か間違っているのか、その両方なのか・・・ この辺りはもう手が出せないのでこれ以上の対応が難しいのですが、ここがなんとかなればこの1対のツールとしても完成すると思っています。


「REST API の標準化」を考える機会がありました。実際に格納したり取得したりするデータ自体の構造は当然ケース・バイ・ケースになるわけですが、その呼び出し方とか、パラメータの指定方法とか、結果のフォーマットとかを社内や団体内で共通化すると、単に便利なだけでなく、一度使った後に新しい別の API を利用する際にも理解を早めることができます。

で、具体的にはどのように共通化すべきで、そこにはどういった要素が考慮されるべきか、といった内容を自分なりに考えてみました。

ここには色んな流派というか、考え方の基本となるパターンがあるのですが、今回は自分の経験を元に、自分はこういう API にしている、こういう API だとわかりやすい/覚えやすい、という基準で、自分なりに標準化したものを紹介します。


【考慮すべき要素】
詳しくは後述しますが、以下の6つについては標準化時に抑えておく必要がある要素であると思っています:

0. id と日付時刻の扱い
1. API をリクエストする際のメソッドと URI
2. API をリクエストする際のパラメータ
3. API からのレスポンス
4. セキュリティ
5. テスト
6. 公開方法



また、以下で説明する内容については、下図のような商品マスターデータ(items)を対象とした REST API を作ることを想定した例として紹介します:
idcategory_idnamemaker_idpriceimage_urlcreatedupdated
x100x051○○シャンプーx10001700http://xxxxx/100.jpg16054028361605402836
x101x051××シャンプーx10002800http://xxxxx/101.png16054038361605403836
x102x052□□コンディショナーx100101000http://xxxxx/102.jpg16054048361605404836
x103x053▲▲ヘアオイルx10001500http://xxxxx/103.jpg16054058361605405836
x104x061◎◎ボディソープx100211000http://xxxxx/104.png16054068361605406836
x105x071◆◆天然化粧水x100102000http://xxxxx/105.png16054078361605408836

※数字は全て integer 。category_id や maker_id は別途 category や maker のマスターデータが存在していて、外部参照キーだけが格納されているイメージです。


【0. id と日付時刻の扱い】
まずは API の考慮点というよりも、その API で対象とするデータにおける考慮点です。既に存在しているデータベース等を対象とする場合は今からの変更は難しいかもしれませんが、新たにデータベースから作成できるのであれば API 利用を想定した設計にしておくべき、という考慮点です。

まずいわゆる id 値について。基本的にはテーブル内でユニークな値であればよいのですが、ここを integer 型とすべきか string 型とすべきか、という考慮点があります。メリット・デメリットを考慮した上で選ぶべきであると思っています:
 メリットデメリット
integer 型・データ量が少ない
・データベース側に自動生成機能があることが多い
・推測しやすい、推測される可能性がある
string 型・存在する id の推測が困難
・値そのものに意味をもたせることも可能(例:メールアドレス)
・1件あたりのデータ量が増える(といっても現代では大したことはないかも)
・生成の仕組みが必要


どちらのケースも存在しているし、どちらか一方に不利な要素があるわけではないのですが、個人的には「今から新規に作るなら string 型」だと思っています。理由は「今では string 型のデメリットが大したことない」のと「 ID が自動生成されるミドルウェアでは string 型になることが多い」ので、結果的に「ID は string 型にした方が統一しやすい」と思っています。

ID に加えて、データレコードの作成日時(created)と最終更新日時(updated)は全てのレコードに加えるべきだと思っています。ソフトデリートを有効にする場合は削除日時(deleted、初期値は 0 か null)も加えます。


なお日付時刻については後述する特別な理由がない限りは UNIX タイムスタンプ値を使うべきです。YYYY-MM-DD のような特定の文字列フォーマットで格納してしまうとタイムゾーンを考慮することができなくなってしまうため、データとしてはタイムスタンプ値で格納し、表示する際に変換する、という方法が理想的です。

※ただし「日本からしか使わない」ことに加えて「特定日だけのデータを取り出す」といった用途がある場合などはあらかじめ日付フォーマット変換しておいた方が便利になることもあります。日付フォーマットを利用する場合は、そのフォーマットもあらかじめ標準化しておくべきです(YYYY-MM-DD とか YYYY-MM-DD hh:mm:ss など)。なお、このあたりは個別事情を考慮して対応する必要があるため、標準化ルールの対象外とする場合もあります。


【1. API をリクエストする際のメソッドと URI】
リクエスト時の考慮ポイントが1番多くあると思っています。順に説明します。

「メソッド」はいわゆる HTTP メソッドのことで、一般的には GET(取得・検索)、POST(作成)、PUT(更新)、DELETE(削除)が用いられます。API の用途や目的に合わせてメソッドを選びます。

より多くの考慮が必要なのは URI 部分となります。まず前提として以下の条件を逸脱しないよう注意してください:
  • 文字コードは UTF-8
  • リクエストデータに外字は使わない
  • URI ではキャメルケース(userData)ではなくスネークケース(user_data)を使う※
  • %(パーセント)でエンコーディングする必要があるデータは URI に含めない
※ホスト名部分が大文字・小文字の区別をしないためです

次にホスト名ですが、理想的にはホスト名の一部に "api" という文字が含まれていることが挙げられます。これが難しい場合はパス名のどこかに "api" を含めて、この URI が API のための URI であることを明示します。以下では api.mycompany.com というホスト名を使う想定で説明を続けます。

パス名の中には今後の仕様変更に対応できるよう、 API のバージョン("v1" など)を含めるようにします。

データの種類(この場合は items)も URI の一部に含まれている必要があります。このあたりから流派によって扱いに違いが出てくる部分ですが、自分は「単数を扱う API なら単数形(item)」、「複数を扱う API なら複数形(items)」としています。そして単数を対象とする場合はその id をパス内で指定するようにします。

例えば以下のようにする、ということです:
  • GET https://api.mycompany.com/v1/items (複数の items を取り出す
  • GET https://api.mycompany.com/v1/item/x100 (id = "x100" の item を取り出す
  • POST https://api.mycompany.com/v1/item (item を1件新規登録する)
  • PUT https://api.mycompany.com/v1/item/x101 (id = "x101" の item を更新する)
  • DELETE https://api.mycompany.com/v1/item/x102 (id = "x102" の item を削除する)
  • POST https://api.mycompany.com/v1/items (items をまとめてバルクインサートする)
  • DELETE https://api.mycompany.com/v1/items (items をまとめてバルクデリートする)
  •   :
リクエストした結果をどのようなフォーマットで取得するか、というフォーマットの指定も(特定フォーマットで固定、ということでなければ)リクエストに含めることができるべきです。一般的には URI の最後に拡張子の形で指定できるようにすることが多いようです:
  • GET https://api.mycompany.com/v1/items.json (複数の items を JSON で取り出す)
  • GET https://api.mycompany.com/v1/items.xml (複数の items を XML で取り出す)
  • GET https://api.mycompany.com/v1/item/x100.json (id = "x100" の item を JSON で取り出す)
  • GET https://api.mycompany.com/v1/item/x100.csv (id = "x100" の item を CSV で取り出す)
  •   :
拡張子が指定されていなかった場合は、エラー扱いとするか、またはあらかじめ決められたデフォルトフォーマットのリクエストに転送されて処理されるようにするか、を決めておきます。

なお、そもそも CSV で取り出すことができないようなデータ構造のオブジェクトを対象とする場合は無理に CSV に対応する必要はないと思っています。

また「検索」や「アップロード」といった処理については別の URI を用意することになります。



【2. API をリクエストする際のパラメータ】
一部 3. で考慮する内容も含まれるのですが、リクエスト時の URL パラメータをどのように標準化するべきかを記載します。

複数のデータが返ってくる可能性のある API を実行する場合、全データ量が膨大にならないようパラメータで制御することがあります。この例を使って以下を紹介します。

一般的には limit パラメータと offset パラメータを用いて取得範囲を指定します。limit は取得件数、offset は「何件目から」を指定するパラメータです。一般的に offset のデフォルト値は 0(1件目から)で、limit のデフォルト値は 100 以下が推奨されています:
  • GET https://api.mycompany.com/v1/items.json?limit=20&offset=100 (items を 100 件目から 20 件、JSON で取り出す)
  •   :

これら以外によく使われるパラメータとしては以下があります。どのようなパラメータに対応すべきかを事前に決めておきます:
パラメータ用途
sortソートキーを指定
since指定タイムスタンプ以降のデータを取り出す
until指定タイムスタンプ以前のデータを取り出す
fields実行結果に含まれるフィールド値を指定したものだけにする(カンマ区切り)


【3. API からのレスポンス】
API の(実行できなかったケースも含めた)実行結果にもある程度の共通化・標準化がされていると、実行後の処理ハンドリングに手間取ることが少なくなります。このレスポンスは (1) 成功した時と、(2) 失敗した時 の両方を考慮した上で標準化する必要があります。ただし KML や iCal, GeoJSON など、フォーマットが規定済みである場合は、そのフォーマットに従うものとします。

考慮点を以下に挙げますが、多くの場合で開発者はまず API を実行し、その結果を見て開発していく、という流れになります。そのため返却された内容で実行結果を判断できるようになっていることが望ましいと考えられます。

まず (1) 成功時のレスポンスデータには以下のような内容が含まれているべきと考えられます:
パラメータ用途
statusHTTP ステータス
resultset全データ件数、offset 値、limit 値
result実行結果(配列)


{
  status: 200,
  resultset: {
    count: 3,
    offset: 10,
    limit: 20
  },
  result: []
}


また (2) エラー時のレスポンスデータには以下の情報を返して原因追求できるようにするべきです:
パラメータ用途
statusHTTP ステータス
typeエラー種別
errorエラー内容


{
  status: 401,
  type: "not authorized",
  error: {
    message: "Not authorized to perform this operation."
  }
}

【4. セキュリティ】
フォーマットの取り決め、という意味での標準化は上述のような感じですが、フォーマット以外にも標準化の対象はあります。その1つがセキュリティ項目です。代表的なものを挙げてみました:
観点対策説明
通信の改ざん、盗聴通信暗号化SSL(https)通信に対応することで送受信データの信頼性担保および情報漏えいの防止を行う。
情報漏えいAPI キーなどによる認証API 利用者に認証をかけることで API を利用できる人を制限する。また利用者毎の利用頻度を確認できるようにすることで API キーが漏洩している可能性を早めに特定できるようになる。アクセストークンを利用する場合はアクセストークンの有効期間を適切に設定して、トークン漏洩時の2次被害を最小にする。
負荷対策利用制限、キャッシュAPI に DDoS 攻撃が行われることを想定した管理が必要。コール数に対する利用制限をかけたり、同一の GET リクエストに対してキャッシュレスポンスで対応する、など
クロスドメイン間の通信CORS 対応ウェブブラウザではクロスサイトスクリプティング防止の観点からクロスドメイン間通信は行わない仕様となっている。場合によってはクロスドメイン間通信を許可する必要が生じ、そのための対応が必要となる




【5. テスト】
API を実際に動かしてテストする上での、テスト環境やテスト方法を標準化することで、テスター担当者の負担を軽減することができます。

一般的には動作を確認できるようなフォームやサンプルプログラムを用意して実際に実行し、そのレスポンスを確認することになります。

なお、6. で後述する Swagger ドキュメントを利用することでテスト用フォームを自動生成することができます。


【6. 公開方法】
API をドキュメント化してテスターや開発者に公開するまでの流れを標準化する、という項目です。このための各種ツールも存在していますが、以下では Swagger ドキュメントを紹介します。

Swagger ドキュメントは Open API Initiative が提供するオープン企画 "OAS" で採用されている REST API のドキュメント化規格です。

Swagger Editor や、YAML による特定フォーマットで API を記述することで、インタラクティブなドキュメント UI を生成することができます。単に URI やパラメータの説明をするだけでなく、実際にAPI を動かすことができる、という点が最大の特徴となっています。開発者視点では実際に API の動作を確認しながら仕様を確認できるのでとても有用な API ドキュメントといえます:
2020111801



【参考】
 内閣官房情報通信技術(IT)総合戦略室  API テクニカルガイドブック

Node.js で XML を扱うのは難しいので、いったん JSON に変換してから扱うことが多いと思っています。そんな場合に自分はよく xml2json というライブラリを使っていました。

xml2json はその名前の通り、XML を JSON に変換してくれるパーサーを実装したライブラリです。使い方は例えば以下のような感じで、XML 文字列をそのまま引数にして実行すると、結果が JSON 文字列となって戻してくれます(JSON の文字列ではなく JSON オブジェクトとして扱う場合は更に JSON.parse() を実行します)。挙動も速く、便利に使っていました:
  :
var parser = require( 'xml2json' );
  :

  :
var xmlStr = fs.readFileSync( xml_filename, 'utf-8' );   //. ファイル名を指定して XML 文字列を取得
var jsonStr = parser.toJson( xmlStr );                   //. XML 文字列を JSON 文字列に変換
var jsonObj = JSON.parse( jsonStr );                     //. JSON 文字列を JSON オブジェクトに変換
  :

ところが上述のような処理を記述した Node.js のソースコードを Windows 環境下で実行しようとした時に問題が発生しました。実行前のライブラリインストール(npm install)の段階でエラーが発生してしまうのでした。詳細なエラーメッセージ等は後述のリンク先を参照していただきたいのですが、node-expat という xml2json の依存ライブラリを node-gyp でビルドする際に何やらエラーが発生していました。

で、この現象を調べた所、どうやら Windows 環境下では xml2json ライブラリ自体がビルドできないという根本的な問題を抱えているようでした:
npm install xml2json error


※厳密には「ビルドできない」わけではないけど、別途 Python や Visual Studio C++ 2012 などの他にインストールする必要があるツールが多く存在しているようです。


↑リンク先でも回避策として「別の XML -> JSON 変換ライブラリを使う」ことが提案されています。というわけで Windows でも使える同機能のライブラリを探したところ、単純な変換であれば fast-xml-parser が使えそうでした。

fast-xml-parser を使う場合は、上述の内容は以下のようなコードになります:
  :
var parser = require( 'fast-xml-parser' );
  :

  :
var xmlStr = fs.readFileSync( xml_filename, 'utf-8' );   //. ファイル名を指定して XML 文字列を取得
var jsonObj = parser.parse( xmlStr );                    //. XML 文字列を JSON オブジェクトに変換
  :

現実問題として自分個人の開発環境として Windows がベースとなることは今のところ考えにくいのですが、(WSL とかではなく)Windows 環境下で開発しないといけない人との共同作業が発生するようなケースではこういったことも意識しないといけないこともでてくると感じています。


画像を表現するフォーマットの1つに SVG(Scalable Vector Graphics) があります。いわゆる「ベクトルデータ」なので、拡大縮小時にもなめらかな曲線で描くことが可能になる、という特徴があります。

この SVG 、実体は特定のルールで記述された XML データとなります。例として以下は 100x100 の2次元エリア内に黒い塗りつぶし三角形を描画しています:
<svg width="100" height="100">
<path d="M0 100 L100 100 L100 0 Z" style="fill:black"/>
</svg>

このような XML データを image/svg+xml の Content-Type を指定して返すことで画像データを動的に生成してクライアントに返すことが可能になります(以下は Node.js での例):
  :

app.get( '/img.svg', function( req, res ){
  res.contentType( 'image/svg+xml' );
  var svg = '<svg width="100" height="100">';
  svg += '<path d="M0 100 L100 100 L100 0 Z" style="fill:black"/>';
  svg += '</svg>';
  res.write( svg );
  res.end();
});

  :

理論的にはこの動的画像を HTML の <img> タグで指定して表示することができる、はず、です:
  :
<img src="/img.svg"/>
  :

ところがこの方法だと正しく表示できません(画像として認識されないようです):
2018053001


<img> タグの src 属性に埋め込んで指定する場合、SVG 側でも xmlns 属性を指定して生成する必要があるようです。つまり SVG 側を以下のように変更します:
<svg xmlns="http://www.w3.org/2000/svg" width="100" height="100">
<path d="M0 100 L100 100 L100 0 Z" style="fill:black"/>
</svg>

コードの場合も同様に変更します:
  :

app.get( '/img.svg', function( req, res ){
  res.contentType( 'image/svg+xml' );
  var svg = '<svg xmlns="http://www.w3.org/2000/svg" width="100" height="100">';
  svg += '<path d="M0 100 L100 100 L100 0 Z" style="fill:black"/>';
  svg += '</svg>';
  res.write( svg );
  res.end();
});

  :

こうした上で <img src="/img.svg"/> とすると正しく表示できるようになりました:
2018053002



このページのトップヘ