VS CodeでXMLのスキーマ検証

Qiitaには２回目の投稿になります。
僕はいわゆる組み込み系の業界に所属していて、普段はC言語やHDLを書いています。
Web系の技術にはかなり疎いのですが、一つだけ、扱えるようになりたい技術があります。

**組み込み系でもXMLを理解したい！**

通信機器の開発に携わると、ほぼ100%と言っていいほどXMLに遭遇します。
XMLは通信規約を表現するのに都合がいいのでしょうね。
たいていの場合、通信規約のスキーマは数千行に及びます。
こんなん理解できんて・・・。
せめて補助ツールがないか探してみたところ、
VS CodeでXMLのスキーマ検証ができることがわかりました。
Red Hatが管理している「XML」プラグインを入れるようです。

これはVS Code使いには朗報！
・・・と思いきや、最初の設定が大変でした。
VS Codeでスキーマ検証機能を有効にするには、XMLの知識が必要だったのです。
おいおい、XMLがわからないからプラグインを導入したのに、本末転倒じゃないか・・・。
数時間の格闘の末、ようやくスキーマ検証機能が使えるようになりました。
せっかく苦労したので、手順を紹介したいと思います。
~~後、XMLに詳しい人がいましたらアドバイスもらえると嬉しいです。~~

# スキーマ検証機能の紹介
はじめに、VS Codeのスキーマ検証で何ができるかを紹介しておきます。
頑張って設定したのに、期待外れだと悲しいですからね。
（GithubからJunitのXSDを拝借しています。）

**１．インテリセンス**
できらぁ！
![インテリセンス.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/628886/00f8fb22-1c03-fddd-e7c0-f0cc182304e1.png)

**２．スキーマの違反チェック**
できらぁっ！！
![スキーマ違反.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/628886/3478ef0d-bc77-bed2-6559-894f80f844d4.png)


凄いですね。まさしく欲しかった機能です。
といいつつ・・・
単にスキーマ検証に対応したツールが欲しいなら、VS Codeじゃなくていい気がします。
僕が試した感じ、同じマイクロソフトの「XML Notepad」、「Visual Studio」の方が簡単に使うことができました。
他、有償ソフトなら Oxygen XML Editorの評判が良さそうです。

それでもVS Codeを裏切ることはできない、という殊勝な方はセットアップに進みましょう。

# セットアップ手順
以下のページを参考に進めました。
https://scrapbox.io/utdh/VSCode%E3%81%A7XML%E3%82%92%E4%BD%BF%E3%81%86

しかし上記ページでは、TEIというスキーマに特化した方法で紹介しています。
本記事では、もう少し汎用的に説明を加えたいと思います。
セットアップのおおまかな手順は以下になります。

* プラグインをインストールする
* JDKをインストールする
* XML & XSDを確認
* catalogの設定

## VS Codeのプラグインをインストールする
VS CodeのExtensionsから、以下プラグインをインストールします。

* 名前：XML
* 説明：XML Language Support by Red Hat
* 開発者：Red Hat

## JDKをインストールする
JDK（またはJRE）version 8 以上をインストールしてください。
これはRed Hatのプラグインが、XML Language Server（LemMinX）を起動するためです。
LemMinXはEclipse上、つまりJAVA上で動作します。
VS Codeは Language Clientとして、Language Severから言語情報を受け取ります。

僕はORACLEの JDK 14.0.2をインストールしました。
インストール後、システム環境変数にJAVA_HOMEを設定します。
JDKのインストール先のフォルダを指定します。
デフォルトでは、以下のようなパスになると思います。

```
C:\Program Files\Java\jdk-14.0.2
```

VS Code側のjdkパス指定はやらなくても大丈夫です。
これでツール側の設定は完了です。

## XML & XSDを確認
・・・さて、ここからXML素人には鬼門です。
XMLを確認するということは、XMLを少し理解する必要があります。
でも大丈夫です。
必要なポイントさえ押さえれば、後は間違い探しの容量でいけるはずです。
検証したいXSD & XMLのペアと、僕が用意したサンプルコードを比較してください。

サンプルコードはめちゃくちゃシンプルにしました。

```Book.xsd
<?xml version='1.0' encoding='UTF-8'?>
<xsd:schema xmlns:xsd="http://www.w3.org/2001/XMLSchema"
           xmlns:tns="http://test/book.com"
           targetNamespace="http://test/book.com">
    <xsd:element name="Book" type="tns:Book"/>
    <xsd:complexType name="Book">
        <xsd:attribute name="title" type="xsd:string" use="required"/>
    </xsd:complexType>
</xsd:schema>
```
```Book.xml
<?xml version='1.0' encoding='UTF-8'?>
<Book   xmlns="http://test/book.com"
        xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
        xsi:schemaLocation="http://test/book.com ./Book.xsd"
        title="XMLBiyori"/>
```
２つのファイルの合計、たったの14行です。
これでもれっきとしたXSD & XMLなので、ちゃんとスキーマ検証は働きます。
サンプルコードを試すには、コピペして、両方のファイルを同一フォルダに置いてください。
Book.xml側の title属性 を消すと、エラーメッセージが出るはずです。

どうでしょうか、簡単にいけそうな気がしませんか！？

### XSDの確認ポイント
先頭のschema要素に注目です。

```Book.xsd
<xsd:schema xmlns:xsd="http://www.w3.org/2001/XMLSchema"
           xmlns:tns="http://test/book.com"
           targetNamespace="http://test/book.com">
```

何が書かれているか、日本語訳してみます。
「xsdという略称で、W3CのXMLSchema名前空間を使います」
「tnsという略称で "http: //test/book.com"の名前空間を使います」
「このXSDの定義は、"http: //test/book.com"の名前空間に適用します」

・・・ふむふむ。とまぁ、日本語にしてもようわかりませんねw
XML素人としては、以下の２点を確認しましょう。

- XSDのschema要素に、上に挙げた属性があること
- XSD内で、固有の名前空間が定義されていること（この例では"http: //test/book.com"ですが、XSD毎に異なります）

これだけで十分です！
もし不足する情報があれば、見様見真似で追加してください。


### XMLの確認ポイント
先頭の要素に注目です。

```Book.xml
<Book   xmlns="http://test/book.com"
        xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
        xsi:schemaLocation="http://test/book.com ./Book.xsd"
```

形式美として、先頭から日本語訳していきます。
「デフォルト名前空間として、"http: //test/book.com"を使います」
「xsiという略称で W3CのXMLSchema-instance名前空間を使います」
「"http:// test/book.com"の名前空間を定義している"./Book.xsd"をスキーマとして使います」

なるほど、なるほど。
なにはともあれ、XML素人としての確認ポイントですw

- XMLに上で挙げた属性があること
- XSDで定義されていた名前空間が、XML内で使われていること（この例では"http: //test/book.com"）
- schemaLocation属性で指定している XSDのパスが正しいこと（この例では"./Book.xsd"）

情報が不足している、情報が間違っている等あれば、見様見真似で修正してください。
（schemaLocation属性が足りないケースが多いと思います）
この例では、XSDのパス指定に相対パスを使っていますが、絶対パスでも大丈夫です。

以上で、確認ポイントの紹介は終わりです。
簡単なXSD & XMLであれば、これでうまくいくと思います！


## catalogの設定
ここから先は、ワンランク上の情報になります。
心してかかってください（素人の域は出ません）。

先ほどの方法でもスキーマ検証は効くのですが、このままでは少し不便です。
XMLがXSDの場所を知らなくてはいけないからです。
XSDの場所が変わると、XMLも書き直す必要が出てきます。

そこで、VS CodeにXSDの場所を登録する、というアプローチを考えます。
**XML catalog** の仕組みを使います。
VS Codeはカタログに登録されたXSDから、自動で適切なものを選択し、XMLのスキーマ検証に利用します。
カタログを登録するには、まず専用のXMLファイルを記述します。
こちらもサンプルコードを用意しました。

```catalog.xml
<?xml version="1.0"?>
<!DOCTYPE catalog
   PUBLIC "-//OASIS/DTD Entity Resolution XML Catalog V1.0//EN"
   "http://www.oasis-open.org/committees/entity/release/1.0/catalog.dtd">
<catalog xmlns="urn:oasis:names:tc:entity:xmlns:xml:catalog">
    <uri name="http://test/book.com" uri="./Book.xsd"/>
</catalog>

```
いろいろ書かれていますが、今回重要なのは以下の記述だけです。

```catalog.xml
    <uri name="http://test/book.com" uri="./Book.xsd"/>
```

XSDが定義している名前空間をname属性に指定、
XSDの場所をuri属性で指定しています。
今回の例では、同一フォルダにcatalog.xmlとBook.xsdを置くので、相対パス指定しています。

カタログの準備ができたら任意のフォルダに配置します。
僕はとりあえず以下フォルダに置くことにしました。
Book.xsdも同一フォルダに置くことをお忘れなく。

```
D:\xml_catalog
```

次にVS Code側の準備です。
XMLプラグインの設定を開き、カタログの場所を登録します。
![カタログ.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/628886/8a9749dc-bd8b-28ec-25d2-2b9c0767f10e.png)

これでカタログの設定は完了です。
Visual Studio Codeをリロードすると、スキーマ検証が働くようになります。
カタログを使うと、XMLの記述を幾分か減らすことができます。

```Book.xml
<?xml version='1.0' encoding='UTF-8'?>
<Book   xmlns="http://test/book.com"
        title="XMLBiyori"/>
```

以上です。
僕が使ってみた感想としては、スキーマ検証の有無では開発効率が段違いです。
XSDを見る頻度は明らかに減ったし、ちょっとしたミスに即座に気づくことができます。
もう普通のエディタに戻ることはできませんw
一つ不満点は、意外とCPUリソースを食うことです。
スキーマのサイズが大きいから仕方ないのかも。
今後のパフォーマンス改善に期待ですね！