プログラミングをしていると、複数のデータをまとめて扱う「リスト(配列)」を使う場面が頻繁にありますよね。
JSONなら[]で簡単に配列を表現できますが、XMLではどうやってリストを書けばいいの? と疑問に思った方も多いはず。実は、XMLにはリストを表現する決まった方法がないため、いくつかのパターンが存在するんです。
この記事では、XMLでリストやコレクションを表現する複数の方法を、それぞれのメリット・デメリットとともに詳しく解説します。実際のコード例も豊富に紹介しますので、XMLデータの設計に迷っている方は、ぜひ参考にしてください!
XMLにおけるリストの基本概念

まず、XMLでリストを扱う際の基本的な考え方を理解しましょう。
JSONとXMLの違い
JSONの場合:
{
"users": [
{"name": "田中太郎", "age": 30},
{"name": "佐藤花子", "age": 25},
{"name": "鈴木次郎", "age": 35}
]
}
配列は[]で明確に表現されていますね。
XMLの場合:
XMLには配列を表す特別な構文がありません。代わりに、要素の繰り返しでリストを表現します。
<users>
<user>
<name>田中太郎</name>
<age>30</age>
</user>
<user>
<name>佐藤花子</name>
<age>25</age>
</user>
<user>
<name>鈴木次郎</name>
<age>35</age>
</user>
</users>
XMLでリストを表現する考え方
XMLでは、同じ名前の要素を繰り返すことで、リストを表現します。
重要なのは:
- コンテナ要素(親要素)でグループ化する
- 各アイテム要素(子要素)を繰り返す
- 命名規則で意図を明確にする
パターン1:複数形/単数形の親子構造(推奨)
最も一般的で推奨される方法です。
基本的な構造
<users>
<user>
<name>田中太郎</name>
<email>tanaka@example.com</email>
</user>
<user>
<name>佐藤花子</name>
<email>sato@example.com</email>
</user>
</users>
構造の説明:
<users>:複数形の親要素(コンテナ)<user>:単数形の子要素(アイテム)- 繰り返される
<user>がリストの各要素
なぜ推奨されるのか
1. 意味が明確
親要素が複数形、子要素が単数形なので、「これはリストだ」と一目で分かります。
2. 構造が美しい
階層構造が整然としていて、人間にもパーサーにも読みやすいです。
3. 拡張性がある
将来、リスト全体に属性を追加したい時も対応しやすいです。
<users total="3" page="1">
<user id="1">
<name>田中太郎</name>
</user>
<user id="2">
<name>佐藤花子</name>
</user>
</users>
実用的な例
商品リスト:
<products>
<product>
<id>P001</id>
<name>ノートパソコン</name>
<price>89800</price>
<stock>15</stock>
</product>
<product>
<id>P002</id>
<name>ワイヤレスマウス</name>
<price>2980</price>
<stock>50</stock>
</product>
<product>
<id>P003</id>
<name>USB-Cケーブル</name>
<price>1280</price>
<stock>100</stock>
</product>
</products>
注文履歴:
<orders>
<order>
<orderId>ORD-2025-001</orderId>
<customer>田中太郎</customer>
<date>2025-01-15</date>
<items>
<item>
<productId>P001</item>
<quantity>1</quantity>
</item>
<item>
<productId>P002</item>
<quantity>2</quantity>
</item>
</items>
</order>
</orders>
ネストしたリスト(リストの中のリスト)も、同じパターンで表現できます。
パターン2:親要素なしの直接繰り返し
親要素を省略して、要素を直接繰り返す方法もあります。
構造例
<root>
<item>値1</item>
<item>値2</item>
<item>値3</item>
</root>
または、ルート要素で直接繰り返す場合もあります(ただし、整形式XMLでは1つのルート要素が必要):
<items>
<item>値1</item>
<item>値2</item>
<item>値3</item>
</items>
メリット
シンプル
階層が浅くなり、XML全体がコンパクトになります。
パース処理が簡単
親要素を気にせず、直接アイテム要素を取得できます。
デメリット
リスト全体への属性付与が困難
コンテナ要素がないため、リスト全体のメタ情報を持たせにくいです。
複数のリストが混在すると混乱
<data>
<user>太郎</user>
<user>花子</user>
<product>商品A</product>
<product>商品B</product>
</data>
どれがどのリストに属するのか分かりにくくなります。
使いどころ
- シンプルな文字列のリスト
- リスト全体のメタ情報が不要な場合
- 単一のリストしか含まないXML
例:タグリスト
<tags>
<tag>プログラミング</tag>
<tag>XML</tag>
<tag>データ構造</tag>
</tags>
パターン3:属性でリスト要素を区別
属性を使って、各アイテムを識別する方法です。
構造例
<users>
<user id="1" name="田中太郎" age="30" email="tanaka@example.com"/>
<user id="2" name="佐藤花子" age="25" email="sato@example.com"/>
<user id="3" name="鈴木次郎" age="35" email="suzuki@example.com"/>
</users>
すべての情報を属性に詰め込むパターンです。
メリット
コンパクト
1行で表現できるため、XMLファイルが短くなります。
軽量
テキストサイズが小さくなり、通信量が削減できます。
デメリット
可読性が低い
属性が多くなると、人間には読みにくくなります。
ネスト構造が作れない
属性は平坦なので、複雑なデータ構造には向きません。
特殊文字の扱いが面倒
属性値には特殊文字のエスケープが必要です。
<!-- 悪い例:属性値に " が含まれる -->
<item description="これは"便利な"商品です"/>
使いどころ
- データがシンプルで平坦な場合
- ファイルサイズを極力小さくしたい場合
- 設定ファイルなど、機械的に処理されるデータ
パターン4:混合型(要素と属性の併用)
要素と属性を組み合わせる、実用的なアプローチです。
構造例
<users>
<user id="1">
<name>田中太郎</name>
<email>tanaka@example.com</email>
<profile>
<age>30</age>
<department>開発部</department>
</profile>
</user>
<user id="2">
<name>佐藤花子</name>
<email>sato@example.com</email>
<profile>
<age>25</age>
<department>営業部</department>
</profile>
</user>
</users>
使い分けのルール:
- 属性:ID、種別、状態など、メタデータ
- 要素:実際の内容、複雑なデータ
メリット
柔軟性が高い
それぞれの特性を活かした設計ができます。
可読性と効率のバランス
重要な情報は要素で詳しく、補助情報は属性でコンパクトに。
実用例
商品カタログ:
<products category="electronics">
<product id="P001" status="available">
<name>ノートパソコン</name>
<description>高性能な15インチモデル</description>
<price currency="JPY">89800</price>
<specifications>
<cpu>Intel Core i7</cpu>
<memory>16GB</memory>
<storage>512GB SSD</storage>
</specifications>
</product>
</products>
ブログ記事:
<posts>
<post id="123" published="true" featured="false">
<title>XMLでリストを扱う方法</title>
<author>山田太郎</author>
<publishedDate>2025-01-15</publishedDate>
<content>
<![CDATA[記事の本文がここに入ります...]]>
</content>
<tags>
<tag>XML</tag>
<tag>プログラミング</tag>
</tags>
</post>
</posts>
空のリストの表現方法
リストに要素が1つもない場合、どう書くべきでしょうか。
方法1:空の親要素
<users>
<!-- アイテムなし -->
</users>
または:
<users/>
最もシンプルで推奨される方法です。
方法2:明示的に空を示す
<users count="0">
<!-- ユーザーなし -->
</users>
属性で「空である」ことを明示する方法。
方法3:nullやemptyを使う
<users>
<empty/>
</users>
または:
<users null="true"/>
あまり推奨されませんが、このような方法もあります。
推奨
空の親要素(方法1)がベストです。XMLパーサーは空要素を自然に扱えますし、コードもシンプルになります。
各プログラミング言語でのXMLリストのパース
実際にコードでどう扱うか見ていきましょう。
Pythonでのパース
import xml.etree.ElementTree as ET
xml_string = '''
<users>
<user>
<name>田中太郎</name>
<age>30</age>
</user>
<user>
<name>佐藤花子</name>
<age>25</age>
</user>
</users>
'''
root = ET.fromstring(xml_string)
# すべてのuserユーザー要素を取得
users = root.findall('user')
for user in users:
name = user.find('name').text
age = user.find('age').text
print(f'{name}: {age}歳')
# 出力:
# 田中太郎: 30歳
# 佐藤花子: 25歳
リスト化する:
user_list = []
for user in root.findall('user'):
user_dict = {
'name': user.find('name').text,
'age': int(user.find('age').text)
}
user_list.append(user_dict)
print(user_list)
# [{'name': '田中太郎', 'age': 30}, {'name': '佐藤花子', 'age': 25}]
JavaScriptでのパース
const xmlString = `
<users>
<user>
<name>田中太郎</name>
<age>30</age>
</user>
<user>
<name>佐藤花子</name>
<age>25</age>
</user>
</users>
`;
const parser = new DOMParser();
const xmlDoc = parser.parseFromString(xmlString, "text/xml");
// すべてのuser要素を取得
const users = xmlDoc.getElementsByTagName('user');
// 配列に変換
const userList = Array.from(users).map(user => {
return {
name: user.getElementsByTagName('name')[0].textContent,
age: parseInt(user.getElementsByTagName('age')[0].textContent)
};
});
console.log(userList);
// [{name: '田中太郎', age: 30}, {name: '佐藤花子', age: 25}]
Javaでのパース
import javax.xml.parsers.*;
import org.w3c.dom.*;
import java.io.StringReader;
import org.xml.sax.InputSource;
import java.util.ArrayList;
import java.util.List;
public class XMLListParser {
public static void main(String[] args) throws Exception {
String xmlString = """
<users>
<user>
<name>田中太郎</name>
<age>30</age>
</user>
<user>
<name>佐藤花子</name>
<age>25</age>
</user>
</users>
""";
DocumentBuilderFactory factory = DocumentBuilderFactory.newInstance();
DocumentBuilder builder = factory.newDocumentBuilder();
Document doc = builder.parse(
new InputSource(new StringReader(xmlString))
);
// すべてのuser要素を取得
NodeList userNodes = doc.getElementsByTagName("user");
List<User> userList = new ArrayList<>();
for (int i = 0; i < userNodes.getLength(); i++) {
Element userElement = (Element) userNodes.item(i);
String name = userElement
.getElementsByTagName("name")
.item(0)
.getTextContent();
int age = Integer.parseInt(
userElement
.getElementsByTagName("age")
.item(0)
.getTextContent()
);
userList.add(new User(name, age));
}
userList.forEach(System.out::println);
}
}
class User {
private String name;
private int age;
public User(String name, int age) {
this.name = name;
this.age = age;
}
@Override
public String toString() {
return name + ": " + age + "歳";
}
}
PHPでのパース
<?php
$xmlString = <<<XML
<users>
<user>
<name>田中太郎</name>
<age>30</age>
</user>
<user>
<name>佐藤花子</name>
<age>25</age>
</user>
</users>
XML;
$xml = simplexml_load_string($xmlString);
$userList = [];
foreach ($xml->user as $user) {
$userList[] = [
'name' => (string)$user->name,
'age' => (int)$user->age
];
}
print_r($userList);
/*
Array
(
[0] => Array
(
[name] => 田中太郎
[age] => 30
)
[1] => Array
(
[name] => 佐藤花子
[age] => 25
)
)
*/
?>
XMLリストのベストプラクティス
実践で使える設計のコツをまとめます。
1. 一貫性のある命名規則
推奨:複数形/単数形のペア
<users>
<user>...</user>
</users>
<products>
<product>...</product>
</products>
<orders>
<order>...</order>
</orders>
避けるべき:不規則な命名
<!-- 悪い例 -->
<userList>
<userItem>...</userItem>
</userList>
<productCollection>
<productData>...</productData>
</productCollection>
2. メタデータは親要素に
リスト全体の情報は、親要素の属性に配置します。
<users total="100" page="1" pageSize="10">
<user id="1">
<name>田中太郎</name>
</user>
<!-- ... -->
</users>
3. IDは属性、内容は要素
識別子やメタ情報は属性、実際のデータは要素に。
<products category="electronics">
<product id="P001" status="active">
<name>商品名</name>
<description>商品説明</description>
<price>10000</price>
</product>
</products>
4. 深すぎる階層を避ける
階層が深くなりすぎると、パースも複雑になります。
悪い例(深すぎる):
<data>
<items>
<itemList>
<itemCollection>
<item>
<itemData>
<itemInfo>
<name>商品名</name>
</itemInfo>
</itemData>
</item>
</itemCollection>
</itemList>
</items>
</data>
良い例(シンプル):
<items>
<item>
<name>商品名</name>
</item>
</items>
5. 名前空間を活用する
複数のリストタイプが混在する場合、名前空間で区別します。
<catalog xmlns:prod="http://example.com/products"
xmlns:cat="http://example.com/categories">
<cat:categories>
<cat:category id="1">電化製品</cat:category>
</cat:categories>
<prod:products>
<prod:product categoryId="1">
<prod:name>ノートパソコン</prod:name>
</prod:product>
</prod:products>
</catalog>
XMLとJSONの比較
リスト表現において、XMLとJSONの違いを見てみましょう。
同じデータの表現
XML:
<users>
<user>
<id>1</id>
<name>田中太郎</name>
<emails>
<email type="work">tanaka@work.com</email>
<email type="personal">tanaka@gmail.com</email>
</emails>
</user>
<user>
<id>2</id>
<name>佐藤花子</name>
<emails>
<email type="work">sato@work.com</email>
</emails>
</user>
</users>
JSON:
{
"users": [
{
"id": 1,
"name": "田中太郎",
"emails": [
{"type": "work", "address": "tanaka@work.com"},
{"type": "personal", "address": "tanaka@gmail.com"}
]
},
{
"id": 2,
"name": "佐藤花子",
"emails": [
{"type": "work", "address": "sato@work.com"}
]
}
]
}
それぞれの特徴
| 特徴 | XML | JSON |
|---|---|---|
| リストの明示性 | 要素の繰り返し | []で明確 |
| ファイルサイズ | 大きめ | 小さめ |
| 可読性 | 冗長だが構造的 | シンプル |
| 型情報 | すべて文字列 | 数値、真偽値を区別 |
| メタデータ | 属性で柔軟 | 限定的 |
| パース速度 | やや遅い | 高速 |
どちらを選ぶべきか
XMLが向いているケース:
- 文書構造が重要(論文、マニュアルなど)
- メタデータが豊富に必要
- レガシーシステムとの互換性
- SOAP APIなどの既存標準
JSONが向いているケース:
- Web APIでのデータ交換
- JavaScriptとの連携
- シンプルなデータ構造
- 軽量・高速が優先
よくある問題とトラブルシューティング
XMLリストで遭遇しやすい問題と解決策です。
問題1:単一要素の時に配列にならない
多くのXMLパーサーで起こる問題です。
XML:
<users>
<user>
<name>田中太郎</name>
</user>
</users>
JavaScript(一部のライブラリ):
// 期待:配列になってほしい
// 実際:オブジェクトになる
{
users: {
user: {name: '田中太郎'} // 配列ではない!
}
}
解決策:
パース後に必ず配列に変換する処理を入れる。
function ensureArray(value) {
return Array.isArray(value) ? value : [value];
}
const users = ensureArray(parsedXML.users.user);
問題2:空リストの扱い
空のリストをどう解釈するか、パーサーによって異なります。
<users>
<!-- 空 -->
</users>
対処法:
コードで明示的にチェックする。
users = root.findall('user')
if not users:
print('ユーザーなし')
else:
for user in users:
# 処理
問題3:属性と要素の混在で混乱
<user id="1" name="田中太郎">
<email>tanaka@example.com</email>
</user>
パースする際、属性と要素を別々に取得する必要があります。
Python:
user = root.find('user')
user_id = user.attrib['id'] # 属性
name = user.attrib['name'] # 属性
email = user.find('email').text # 要素
XMLスキーマでリストを定義する
XMLスキーマ(XSD)を使って、リストの構造を定義できます。
基本的なリストの定義
<?xml version="1.0" encoding="UTF-8"?>
<xs:schema xmlns:xs="http://www.w3.org/2001/XMLSchema">
<!-- usersリストの定義 -->
<xs:element name="users">
<xs:complexType>
<xs:sequence>
<!-- user要素が0回以上繰り返される -->
<xs:element name="user" minOccurs="0" maxOccurs="unbounded">
<xs:complexType>
<xs:sequence>
<xs:element name="name" type="xs:string"/>
<xs:element name="age" type="xs:integer"/>
</xs:sequence>
</xs:complexType>
</xs:element>
</xs:sequence>
</xs:complexType>
</xs:element>
</xs:schema>
重要な属性:
minOccurs="0":最小0個(空リストOK)maxOccurs="unbounded":上限なし(無制限に繰り返せる)
固定長リストの定義
<!-- 必ず3つの要素を持つリスト -->
<xs:element name="items">
<xs:complexType>
<xs:sequence>
<xs:element name="item" type="xs:string"
minOccurs="3" maxOccurs="3"/>
</xs:sequence>
</xs:complexType>
</xs:element>
まとめ:XMLリストの設計指針
XMLでリストを表現する方法をまとめます。
基本パターン:
1. 複数形/単数形の親子構造(最推奨)
<users>
<user>...</user>
<user>...</user>
</users>
2. 直接繰り返し(シンプルなリスト向け)
<items>
<item>値1</item>
<item>値2</item>
</items>
3. 混合型(実用的)
<users total="2">
<user id="1">
<name>太郎</name>
</user>
</users>
設計のベストプラクティス:
- 一貫性のある命名規則を使う
- メタデータは親要素の属性に
- IDや種別は属性、内容は要素に
- 階層を深くしすぎない
- 空リストは空の親要素で表現
パース時の注意点:
- 単一要素の時の配列化処理
- 空リストのチェック
- 属性と要素の区別
- 言語・ライブラリごとの違いを把握
XMLとJSONの使い分け:
- 文書構造・メタデータ重視 → XML
- シンプル・軽量・Web API → JSON
XMLでリストを扱う際は、「配列の明示的な構文がない」という特性を理解した上で、読みやすく保守しやすい構造を心がけましょう。この記事で紹介したパターンを参考に、あなたのプロジェクトに最適な設計を選んでください!
関連キーワード: XML、リスト、配列、コレクション、要素の繰り返し、親子構造、XMLスキーマ、XSD、JSON比較、パース、複数形単数形、データ構造、階層構造、ベストプラクティス

コメント