レガシーなエンタープライズAPIを使ったことがある、RSSフィードを消費したことがある、.docxファイルを開いたことがある、 またはSVGを描いたことがあるなら、知らないうちにXMLを使っていたかもしれません。XMLは多くの開発者が思うよりも、 ソフトウェアの世界の多くを支えています。JSONより古く、より冗長で、より複雑ですが、特定のコンテキストでは より強力でもあります。これはXMLとは実際に何か、どのように機能するか、そしていつ使うのが理にかなっているかについての実践的なガイドです。

XMLはeXtensible Markup Language(拡張可能なマークアップ言語)の略です。 W3CはXML 1.0仕様を1998年に公開し、 ウェブの初期時代における支配的なデータ交換フォーマットとなりました。「拡張可能」という部分が重要です: 固定されたタグセットを持つHTMLとは異なり、XMLでは必要なデータ構造を記述するために独自のタグを定義できます。

XMLの見た目

以下はeコマースAPIからの商品を表す完全なXMLドキュメントです。これにより、 遭遇するすべての主要な構文機能が網羅されます:

xml
<?xml version="1.0" encoding="UTF-8"?>
<product id="SKU-8821" inStock="true">
  <name>Wireless Noise-Cancelling Headphones</name>
  <brand>SoundCore</brand>
  <price currency="USD">149.99</price>
  <categories>
    <category>Electronics</category>
    <category>Audio</category>
    <category>Accessories</category>
  </categories>
  <specs>
    <spec name="battery">30 hours</spec>
    <spec name="connectivity">Bluetooth 5.2</spec>
    <spec name="weight">250g</spec>
  </specs>
  <description>
    Premium wireless headphones with active noise cancellation,
    30-hour battery life, and foldable design.
  </description>
</product>

主要な部分を分解してみましょう。最初の行はXML宣言です — これはXML 1.0でUTF-8でエンコードされていることをパーサーに伝えます。 <product>タグはルート要素です(すべてのXMLドキュメントにはちょうど1つあります)。 同じタグ上のidinStockの部分は属性です。 開始タグと終了タグの中にあるものはすべて、子要素、属性、またはテキストコンテンツです。

要素 vs 属性 — 本物の設計上の決断

新しいXML作成者を戸惑わせることの1つ:同じデータを要素としても属性としても表現できます。 以下の両方とも同じデータの有効なXMLです:

xml
<!-- 属性として -->
<price currency="USD">149.99</price>

<!-- 子要素として -->
<price>
  <amount>149.99</amount>
  <currency>USD</currency>
</price>

従来の知恵:要素についてのメタデータ(識別子、フラグ、単位)には属性を使用し、 実際のデータコンテンツには子要素を使用します — 特にそのコンテンツが将来複雑になったり、 繰り返されたり、独自の属性が必要になる可能性がある場合はそうです。 属性はプレーンテキストのみを保持できますが、子要素は任意のXML構造を保持できます。

整形式 vs 有効 — 2つの異なる基準

XMLには混同されやすい2つの正確さのレベルがあります:

  • 整形式XMLは基本的な構文ルールに従っています:1つのルート要素、すべてのタグが適切に閉じられている、属性が引用符で囲まれている、不正な文字がない。すべてのXMLパーサーがこれを確認できます。
  • 有効なXMLは特定のスキーマ(DTD(ドキュメント型定義)またはXMLスキーマ(XSD))に準拠しています。有効性の確認にはドキュメントとスキーマの両方が必要です。整形式でありながら特定のスキーマに対して有効でないXMLが存在することがあります。
実際には:ほとんどのエンタープライズXML統合は整形式だけでなく有効性を重視します。 SOAP統合を構築したり、HL7ヘルスケアレコードを交換したりする場合、 スキーマはどの要素が必要か、どの型を保持するか、どの値が許可されるかを正確に定義します。 整形式を素早く確認するにはXMLバリデーターを使用してください。

実世界でXMLが現れる場所

  • SOAPウェブサービス。エンタープライズソフトウェアの古い半分は今でもSOAPで動いています — 銀行API、ERPシステム、決済ゲートウェイ。すべてのSOAPメッセージはEnvelope、Header、Bodyを持つ定義済みのXMLドキュメントです。
  • RSSおよびAtomフィード。すべてのポッドキャストフィード、ニュースサイトフィード、YouTubeチャンネルサブスクリプションはXMLドキュメントです。RSS 2.0とAtomはどちらも2000年代初頭から存在するXMLベースのフォーマットです。
  • SVG画像。スケーラブルベクターグラフィックスはXMLです。テキストエディタで.svgファイルを開くとXMLを読んでいることになります。これがSVGをCSSでスタイリングしてJavaScriptで操作できる理由です。
  • Officeドキュメント。.docx.xlsx、または.pptxファイルはXMLファイルを含むZIPアーカイブです。Office Open XMLはMicrosoftがすべての最新Officeドキュメントフォーマットを保存する方法です。
  • Androidレイアウト。AndroidのUIレイアウトはXMLファイルで定義されています。Android開発を行ったことがあれば、多くのXMLを書いたことになります。
  • Mavenとpom.xml。JavaのMavenビルドシステムはpom.xmlファイルを使用してプロジェクトの依存関係とビルド設定を定義します — すべてのJava開発者に馴染みがあるはずです。

JavaScriptでXMLを解析する — DOMParser

ブラウザでは、組み込みの DOMParser APIを使用してXML文字列を解析できます。HTMLの解析と同じように動作します:

js
const xmlString = `<?xml version="1.0"?>
<product id="SKU-8821">
  <name>Wireless Headphones</name>
  <price currency="USD">149.99</price>
  <categories>
    <category>Electronics</category>
    <category>Audio</category>
  </categories>
</product>`;

const parser = new DOMParser();
const doc = parser.parseFromString(xmlString, 'application/xml');

// 解析エラーを確認
const parseError = doc.querySelector('parsererror');
if (parseError) {
  console.error('XML解析エラー:', parseError.textContent);
} else {
  const name = doc.querySelector('name').textContent;
  const currency = doc.querySelector('price').getAttribute('currency');
  const categories = [...doc.querySelectorAll('category')].map(el => el.textContent);

  console.log(name);       // Wireless Headphones
  console.log(currency);   // USD
  console.log(categories); // ['Electronics', 'Audio']
}

PythonでXMLを解析する — ElementTree

Pythonの標準ライブラリには xml.etree.ElementTree が含まれています — 基本的なXML解析にサードパーティパッケージは不要です:

python
import xml.etree.ElementTree as ET

xml_string = """<?xml version="1.0"?>
<product id="SKU-8821">
  <name>Wireless Headphones</name>
  <price currency="USD">149.99</price>
  <categories>
    <category>Electronics</category>
    <category>Audio</category>
  </categories>
</product>"""

root = ET.fromstring(xml_string)

name = root.find('name').text
currency = root.find('price').get('currency')
categories = [el.text for el in root.findall('categories/category')]

print(name)        # Wireless Headphones
print(currency)    # USD
print(categories)  # ['Electronics', 'Audio']

XMLの作者が陥りやすい落とし穴

  • エンティティエンコーディング。XMLのテキストと属性値では5つの文字をエスケープする必要があります:&&amp;<&lt;>&gt;"&quot;'&apos;。URLのアンパサンドのエスケープを忘れるとドキュメント全体が壊れます。
  • 名前空間。名前空間付きXML<soap:Envelope xmlns:soap="...">のように見えます。名前空間を考慮しないクエリは要素を見つけることができません。これはXML解析で最も一般的なバグの1つです。
  • 空白の扱い。XMLでは要素間の空白は技術的に意味があります(HTMLとは異なり)。ほとんどのパーサーは合理的に処理しますが、ドキュメントを比較する際に予期しない結果を引き起こすことがあります。
  • 文字エンコーディング。XML宣言は実際のファイルエンコーディングと一致する必要があります。ISO-8859-1として宣言されたUTF-8ファイルは、非ASCII文字に対して正しく解析されません。
  • ネイティブな配列型がない。XMLには配列がありません。要素を繰り返すことでリストを表現します。これはパーサーがJavaScript配列ではなくNodeListsを返すことを意味します — 常にArray.from()またはスプレッドで変換してください。

知っておくべきXMLツール

XMLを定期的に扱う場合、これらのツールが時間を節約してくれます: XMLフォーマッターでミニファイされたXMLレスポンスを整形し、 XMLバリデーターで整形式を確認し、 XML to JSONでXMLレスポンスをJSONに変換して扱いやすくし、 XML XPathでドキュメントに対してXPathクエリをテストできます。

まとめ

XMLはJSONに比べて冗長で複雑ですが、レガシーな注釈に過ぎないわけではありません — SVG、Officeドキュメント、 RSSフィード、SOAPサービス、AndroidのUIの基盤です。要素と属性の区別、整形式と有効なXMLの違い、 そしてエンティティエンコーディングと名前空間に関する一般的な落とし穴を理解することは、 仕事でXMLが出てくるたびに役立ちます。 そして必ず出てくるでしょう。