XML通信とは?データのやり取りにXMLを使う方法を初心者向けに解説

プログラミング・IT
スポンサーリンク

XML通信って何?

XML通信とは、インターネットやネットワークを通じて、XML形式でデータをやり取りすることです。

アプリケーション同士がデータを交換する時、人間が読める形式で構造化されたデータが必要になることがあります。そんな時にXMLが活躍するんです。

例えば、天気予報アプリが気象データを取得する時、ネットショッピングサイトが在庫情報を確認する時など、様々な場面でXML通信が使われています。

なぜXMLで通信するの?

理由1:構造化されたデータを送れる

XMLは階層構造を持つデータを表現できます。複雑な情報も整理して送受信できるんです。

例:顧客情報を送信

<customer>
    <name>山田太郎</name>
    <email>yamada@example.com</email>
    <address>
        <postal>123-4567</postal>
        <prefecture>東京都</prefecture>
        <city>渋谷区</city>
    </address>
</customer>

この構造なら、住所が複数の要素で構成されていても、きれいに表現できますね。

理由2:人間が読める形式

XMLはテキスト形式なので、送られたデータを目で見て確認できます。デバッグや問題解決が楽になるでしょう。

理由3:プラットフォーム非依存

JavaでもPythonでもPHPでも、どのプログラミング言語でもXMLは扱えます。異なるシステム間でのデータ交換に適しているんです。

理由4:標準化されている

XMLは国際規格として標準化されているため、多くのツールやライブラリが利用できます。

XML通信の主な方式

XMLを使った通信には、いくつかの代表的な方式があります。

1. SOAP(ソープ)通信

SOAP(Simple Object Access Protocol)は、XMLを使った通信プロトコルです。主に企業向けシステムで使われています。

SOAPの特徴:

  • 厳密な規格に基づく
  • セキュリティ機能が充実
  • 複雑な処理に対応できる
  • 金融システムなど信頼性が重要な場面で活用

SOAP通信の例:

<?xml version="1.0" encoding="UTF-8"?>
<soap:Envelope xmlns:soap="http://schemas.xmlsoap.org/soap/envelope/">
    <soap:Header>
        <authentication>
            <username>user123</username>
            <token>abc123xyz</token>
        </authentication>
    </soap:Header>
    <soap:Body>
        <getWeatherRequest>
            <city>Tokyo</city>
            <date>2024-12-15</date>
        </getWeatherRequest>
    </soap:Body>
</soap:Envelope>

SOAPメッセージは、Envelope(封筒)、Header(ヘッダー)、Body(本文)という構造を持ちます。

2. REST API でのXML使用

REST(Representational State Transfer)は、シンプルなWeb通信の設計スタイルです。REST APIでは、JSONがよく使われますが、XMLも利用できます。

RESTでのXML通信の例:

リクエスト(商品情報の取得):

GET /api/products/123 HTTP/1.1
Host: example.com
Accept: application/xml

レスポンス:

<?xml version="1.0" encoding="UTF-8"?>
<product>
    <id>123</id>
    <name>ワイヤレスマウス</name>
    <price>3000</price>
    <stock>50</stock>
    <category>PC周辺機器</category>
</product>

3. XMLHttpRequest(Ajax通信)

ブラウザからサーバーへ非同期にデータを送受信する時に使います。Ajax(Asynchronous JavaScript and XML)という技術の一部です。

Webページを再読み込みせずに、バックグラウンドでデータを取得・送信できるんです。

4. RSS/Atomフィード

ブログやニュースサイトの更新情報を配信する時に使われるXML形式です。

RSSの例:

<?xml version="1.0" encoding="UTF-8"?>
<rss version="2.0">
    <channel>
        <title>テックニュース</title>
        <link>https://example.com</link>
        <description>最新のIT情報をお届け</description>
        <item>
            <title>AI技術の最新動向</title>
            <link>https://example.com/article1</link>
            <pubDate>Mon, 15 Dec 2024 10:00:00 +0900</pubDate>
            <description>人工知能技術の最新トレンドについて</description>
        </item>
    </channel>
</rss>

XMLをHTTPで送受信する方法

実際のプログラムでXMLデータを送受信する方法を見ていきましょう。

Pythonでの送信と受信

Requestsライブラリを使った送信:

import requests
import xml.etree.ElementTree as ET

# XMLデータを作成
root = ET.Element('order')
item = ET.SubElement(root, 'item')
item.text = 'ノートパソコン'
quantity = ET.SubElement(root, 'quantity')
quantity.text = '1'

xml_data = ET.tostring(root, encoding='utf-8')

# XMLをPOSTで送信
headers = {'Content-Type': 'application/xml'}
response = requests.post('https://api.example.com/orders', 
                        data=xml_data, 
                        headers=headers)

# レスポンスを受信
if response.status_code == 200:
    response_xml = ET.fromstring(response.content)
    order_id = response_xml.find('orderId').text
    print(f'注文ID: {order_id}')

XMLレスポンスの受信:

import requests
import xml.etree.ElementTree as ET

# XMLデータを取得
headers = {'Accept': 'application/xml'}
response = requests.get('https://api.example.com/products/123', 
                       headers=headers)

# XMLをパース
if response.status_code == 200:
    root = ET.fromstring(response.content)
    product_name = root.find('name').text
    price = root.find('price').text
    print(f'商品名: {product_name}, 価格: {price}円')

JavaScriptでの送信と受信(ブラウザ)

Fetch APIを使った方法:

// XMLデータを作成
const xmlString = `
<?xml version="1.0" encoding="UTF-8"?>
<order>
    <item>ノートパソコン</item>
    <quantity>1</quantity>
</order>
`;

// XMLをPOSTで送信
fetch('https://api.example.com/orders', {
    method: 'POST',
    headers: {
        'Content-Type': 'application/xml'
    },
    body: xmlString
})
.then(response => response.text())
.then(xmlText => {
    // XMLレスポンスをパース
    const parser = new DOMParser();
    const xmlDoc = parser.parseFromString(xmlText, 'text/xml');

    const orderId = xmlDoc.getElementsByTagName('orderId')[0].textContent;
    console.log('注文ID:', orderId);
})
.catch(error => {
    console.error('エラー:', error);
});

XMLHttpRequestを使った従来の方法:

const xhr = new XMLHttpRequest();

xhr.open('GET', 'https://api.example.com/products/123', true);
xhr.setRequestHeader('Accept', 'application/xml');

xhr.onload = function() {
    if (xhr.status === 200) {
        const xmlDoc = xhr.responseXML;
        const productName = xmlDoc.getElementsByTagName('name')[0].textContent;
        const price = xmlDoc.getElementsByTagName('price')[0].textContent;
        console.log(`商品名: ${productName}, 価格: ${price}円`);
    }
};

xhr.send();

PHPでの送信と受信

cURLを使った送信:

<?php
// XMLデータを作成
$xml = new SimpleXMLElement('<order/>');
$xml->addChild('item', 'ノートパソコン');
$xml->addChild('quantity', '1');
$xml_string = $xml->asXML();

// cURLで送信
$ch = curl_init('https://api.example.com/orders');
curl_setopt($ch, CURLOPT_POST, true);
curl_setopt($ch, CURLOPT_POSTFIELDS, $xml_string);
curl_setopt($ch, CURLOPT_RETURNTRANSFER, true);
curl_setopt($ch, CURLOPT_HTTPHEADER, [
    'Content-Type: application/xml'
]);

$response = curl_exec($ch);
curl_close($ch);

// レスポンスをパース
$response_xml = simplexml_load_string($response);
$order_id = (string)$response_xml->orderId;
echo "注文ID: {$order_id}";
?>

XMLレスポンスの受信:

<?php
// XMLデータを取得
$ch = curl_init('https://api.example.com/products/123');
curl_setopt($ch, CURLOPT_RETURNTRANSFER, true);
curl_setopt($ch, CURLOPT_HTTPHEADER, [
    'Accept: application/xml'
]);

$response = curl_exec($ch);
curl_close($ch);

// XMLをパース
$xml = simplexml_load_string($response);
$product_name = (string)$xml->name;
$price = (string)$xml->price;
echo "商品名: {$product_name}, 価格: {$price}円";
?>

HTTPヘッダーの設定

XML通信では、HTTPヘッダーで適切なContent-Type(コンテンツタイプ)を指定する必要があります。

主なContent-Type:

  • application/xml:一般的なXMLデータ
  • text/xml:テキスト形式のXML
  • application/soap+xml:SOAPメッセージ
  • application/rss+xml:RSSフィード
  • application/atom+xml:Atomフィード

送信時のヘッダー例:

POST /api/orders HTTP/1.1
Host: example.com
Content-Type: application/xml
Content-Length: 150

<?xml version="1.0"?>
<order>
    <item>商品A</item>
</order>

受信時のヘッダー例:

GET /api/products/123 HTTP/1.1
Host: example.com
Accept: application/xml

Acceptヘッダーで「XMLで返してください」とサーバーに伝えることができます。

XML通信のセキュリティ対策

XMLで通信する時は、セキュリティに注意が必要です。

1. HTTPS(SSL/TLS)を使う

XMLデータは平文(暗号化されていないテキスト)なので、HTTPSで暗号化しましょう。

良い例:

https://api.example.com/orders

悪い例:

http://api.example.com/orders

2. XML爆弾(Billion Laughs攻撃)への対策

悪意のあるXMLで、サーバーのメモリを大量に消費させる攻撃があります。

攻撃例(絶対に使わないでください):

<!DOCTYPE lolz [
  <!ENTITY lol "lol">
  <!ENTITY lol2 "&lol;&lol;&lol;&lol;&lol;&lol;&lol;&lol;&lol;&lol;">
]>
<lolz>&lol2;</lolz>

対策:

  • 外部エンティティを無効化する
  • XMLパーサーのセキュリティ設定を確認
  • 入力サイズを制限する

Pythonでの対策:

import xml.etree.ElementTree as ET

# defusedxmlライブラリを使う(推奨)
import defusedxml.ElementTree as DefusedET

# 安全にパース
tree = DefusedET.parse('untrusted.xml')

3. XXE(XML External Entity)攻撃への対策

外部ファイルを読み込ませる攻撃を防ぎます。

攻撃例(絶対に使わないでください):

<!DOCTYPE foo [
  <!ENTITY xxe SYSTEM "file:///etc/passwd">
]>
<data>&xxe;</data>

対策:
XMLパーサーで外部エンティティの処理を無効化します。

4. 入力検証

受信したXMLデータは、必ず検証しましょう。

import xml.etree.ElementTree as ET

def validate_xml(xml_string):
    try:
        root = ET.fromstring(xml_string)

        # 必須要素の存在確認
        if root.find('item') is None:
            return False

        # データ型の検証
        quantity = root.find('quantity')
        if quantity is not None:
            try:
                int(quantity.text)
            except ValueError:
                return False

        return True
    except ET.ParseError:
        return False

エラーハンドリング

XML通信では、様々なエラーが発生する可能性があります。

通信エラーの処理

Pythonの例:

import requests
import xml.etree.ElementTree as ET

try:
    response = requests.get('https://api.example.com/data', timeout=10)
    response.raise_for_status()  # ステータスコードが200番台以外は例外

    xml_data = ET.fromstring(response.content)

except requests.exceptions.Timeout:
    print('タイムアウトしました')
except requests.exceptions.ConnectionError:
    print('接続エラーが発生しました')
except requests.exceptions.HTTPError as e:
    print(f'HTTPエラー: {e}')
except ET.ParseError:
    print('XMLのパースに失敗しました')
except Exception as e:
    print(f'予期しないエラー: {e}')

エラーレスポンスの例

API側からエラーをXMLで返すこともあります。

エラーレスポンスの例:

<?xml version="1.0" encoding="UTF-8"?>
<error>
    <code>400</code>
    <message>不正なリクエストです</message>
    <details>
        <field>email</field>
        <reason>メールアドレスの形式が正しくありません</reason>
    </details>
</error>

エラー処理の実装:

def handle_api_response(response):
    if response.status_code == 200:
        return ET.fromstring(response.content)
    else:
        error_xml = ET.fromstring(response.content)
        code = error_xml.find('code').text
        message = error_xml.find('message').text
        raise Exception(f'APIエラー [{code}]: {message}')

JSONとの比較

最近のWeb APIでは、XMLよりもJSON(JavaScript Object Notation)がよく使われます。どちらを選ぶべきか見てみましょう。

XMLのメリット

  • 複雑な階層構造を表現しやすい
  • 属性とテキストの両方を持てる
  • スキーマ定義が充実(XSDなど)
  • 名前空間で衝突を回避できる
  • コメントを書ける

XMLのデメリット

  • ファイルサイズが大きくなりがち
  • パースに時間がかかる
  • 書き方が冗長

JSONのメリット

  • シンプルで軽量
  • JavaScriptとの親和性が高い
  • パースが高速
  • 人間にも読みやすい

どちらを選ぶ?

XMLを選ぶべき場合:

  • SOAP通信を使う必要がある
  • 複雑なデータ構造を扱う
  • スキーマ定義による厳密な検証が必要
  • 既存システムがXMLを使用している

JSONを選ぶべき場合:

  • REST APIを新規開発する
  • モバイルアプリやWebアプリでデータを扱う
  • シンプルなデータ構造
  • パフォーマンスを重視

実践的な使用例

例1:天気情報APIの利用

import requests
import xml.etree.ElementTree as ET

def get_weather(city):
    url = f'https://api.weather.example.com/forecast'
    params = {'city': city, 'format': 'xml'}

    try:
        response = requests.get(url, params=params, timeout=10)
        response.raise_for_status()

        root = ET.fromstring(response.content)

        temperature = root.find('.//temperature').text
        condition = root.find('.//condition').text
        humidity = root.find('.//humidity').text

        return {
            'temperature': temperature,
            'condition': condition,
            'humidity': humidity
        }
    except Exception as e:
        print(f'エラー: {e}')
        return None

# 使用例
weather = get_weather('Tokyo')
if weather:
    print(f"気温: {weather['temperature']}℃")
    print(f"天候: {weather['condition']}")
    print(f"湿度: {weather['humidity']}%")

例2:在庫管理システムとの連携

<?php
function update_inventory($product_id, $quantity) {
    // XMLリクエストを作成
    $xml = new SimpleXMLElement('<inventoryUpdate/>');
    $xml->addChild('productId', $product_id);
    $xml->addChild('quantity', $quantity);
    $xml->addChild('timestamp', date('Y-m-d H:i:s'));

    $xml_string = $xml->asXML();

    // APIに送信
    $ch = curl_init('https://inventory.example.com/api/update');
    curl_setopt($ch, CURLOPT_POST, true);
    curl_setopt($ch, CURLOPT_POSTFIELDS, $xml_string);
    curl_setopt($ch, CURLOPT_RETURNTRANSFER, true);
    curl_setopt($ch, CURLOPT_HTTPHEADER, [
        'Content-Type: application/xml',
        'Authorization: Bearer your_token_here'
    ]);

    $response = curl_exec($ch);
    $status = curl_getinfo($ch, CURLINFO_HTTP_CODE);
    curl_close($ch);

    if ($status === 200) {
        $response_xml = simplexml_load_string($response);
        return (string)$response_xml->status === 'success';
    }

    return false;
}

// 使用例
if (update_inventory('PROD-123', 50)) {
    echo '在庫更新に成功しました';
} else {
    echo '在庫更新に失敗しました';
}
?>

まとめ

XML通信は、異なるシステム間でデータをやり取りする標準的な方法です。

XML通信の主な方式:

  • SOAP:企業向けの厳密な通信プロトコル
  • REST API:シンプルなWeb API
  • Ajax:ブラウザからの非同期通信
  • RSS/Atom:フィード配信

実装のポイント:

  • 適切なHTTPヘッダーを設定する
  • HTTPSで通信を暗号化する
  • セキュリティ対策を実施する
  • エラーハンドリングを適切に行う

セキュリティの注意点:

  • HTTPS(SSL/TLS)を使用
  • 外部エンティティを無効化
  • 入力検証を行う
  • defusedxmlなどの安全なライブラリを使用

XMLは冗長で古い技術と思われがちですが、企業システムや複雑なデータ構造を扱う場面では今でも広く使われています。基本をしっかり理解して、適切な場面で活用していきましょう。

コメント

タイトルとURLをコピーしました