技術資料

PHPでXMLを読み込む:SimpleXMLで要素・属性・名前空間を取得する

作成日:2026.09.11

PHP

PHPのSimpleXMLを使ってXMLファイルを読み込み、要素や属性、繰り返し要素、名前空間付きの要素を取得する方法を解説します。XPathによる検索結果を配列へ変換する処理に加え、解析失敗、欠損値、文字コード、外部XMLを扱う場合の注意点も紹介します。

PHP 8.3のSimpleXMLを使って、XMLファイルを読み込む手順を解説します。XMLの要素や属性、繰り返し要素、名前空間付きの要素を取得して、アプリケーションで扱いやすい配列へ変換してみます。

SimpleXMLは、XMLの構造がある程度決まっていて、必要な要素を順番に読み取る処理に向いています。XML全体をメモリへ読み込むため、非常に大きなXMLをストリーム処理する場合は、XMLReaderなど別の方法も検討した方が良いかもしれません。

前提

今回の動作確認環境は以下の通りです。

  • OS: Windows 11
  • PHP: 8.3.15 CLI
  • ターミナル: PowerShell
  • 使用する拡張: SimpleXML、libxml
  • 入力: ローカルに保存したXMLファイル

PHPのSimpleXML拡張は、XMLをSimpleXMLElementオブジェクトへ読み込み、要素名を使って子要素へアクセスできる機能です。要素の値は文字列として取り出して利用し、属性はattributes()、複数の子要素はforeachで処理します。

なお、XMLを読み込めたことと、期待する要素が存在することは別に確認します。解析に成功していても、データの構造が想定と異なれば必要な値は取得できません。

今回使うXMLファイルを用意する

まず、PHPスクリプトと同じディレクトリにサンプルデータとしてcatalog.xmlを作成します。書籍を表すbook要素を複数用意し、属性、著者の繰り返し要素、名前空間付きの出版日を含めます。

<?xml version="1.0" encoding="UTF-8"?>
<catalog xmlns:meta="https://example.com/catalog/meta">
    <book id="book-001" category="technical">
        <title>PHPでWeb APIを呼び出す</title>
        <authors>
            <author>山田太郎</author>
            <author>佐藤花子</author>
        </authors>
        <meta:published>2026-09-01</meta:published>
    </book>
    <book id="book-002" category="database">
        <title>SQLの基本</title>
        <authors>
            <author>鈴木一郎</author>
        </authors>
        <meta:published>2026-09-05</meta:published>
    </book>
</catalog>

ルート要素のxmlns:metaは、metaという接頭辞に名前空間URIを割り当てています。名前空間は、異なるXML仕様で同じ要素名が使われる場合などに、要素の所属を区別するために使います。

XMLファイルをSimpleXMLへ読み込む

XMLファイルを読み込むには、simplexml_load_file()を使います。読み込みに成功するとSimpleXMLElementが返り、失敗するとfalseが返ります。

解析エラーを画面へ直接表示せず、処理側で確認できるようにするため、libxml_use_internal_errors()を使います。ローカルファイルだけを扱うため、XMLの読み込み時にはLIBXML_NONETも指定します。

<?php

function loadXml(string $file): SimpleXMLElement
{
    if (!is_file($file) || !is_readable($file)) {
        throw new RuntimeException('XMLファイルを読み込めません。');
    }

    $previousUseErrors = libxml_use_internal_errors(true);
    libxml_clear_errors();

    try {
        $xml = simplexml_load_file(
            $file,
            SimpleXMLElement::class,
            LIBXML_NONET
        );
        $parseErrors = libxml_get_errors();
    } finally {
        libxml_clear_errors();
        libxml_use_internal_errors($previousUseErrors);
    }

    if ($xml === false) {
        $message = $parseErrors[0]->message ?? 'XMLの解析に失敗しました。';
        throw new RuntimeException(trim($message));
    }

    return $xml;
}

$xml = loadXml(__DIR__ . '/catalog.xml');

libxml_use_internal_errors()は、呼び出し前の設定を保存して、処理が終わった後に元へ戻しています。共通処理の中で一時的に設定を変更する場合は、呼び出し元へ影響を残さないようにします。

また、LIBXML_NONETは、ドキュメントの読み込み時にネットワークアクセスを無効にするオプションです。今回のようにローカルファイルを扱う処理では、不要なネットワークアクセスをさせないために指定しています。

要素の値と属性を取得する

読み込んだXMLの子要素は、要素名を使って参照できます。SimpleXMLElementはそのままでは文字列ではないため、要素の値を表示したり配列へ入れたりするときは、文字列へキャストします。

$book = $xml->book[0];

echo (string) $book->title, PHP_EOL;
// PHPでWeb APIを呼び出す

$attributes = $book->attributes();

echo (string) $attributes['id'], PHP_EOL;
// book-001

echo (string) $attributes['category'], PHP_EOL;
// technical

$xml->book[0]の[0]は、複数あるbook要素の最初の要素を表します。属性は配列のように参照できますが、属性が必ず存在するとは限らない場合は、値の有無を確認してから利用します。

繰り返し要素を処理する

著者のように同じ要素が複数ある場合は、foreachで繰り返し処理できます。SimpleXMLElementのプロパティは通常のPHP配列ではありませんが、複数の要素を反復処理できます。

foreach ($book->authors->author as $author) {
    echo trim((string) $author), PHP_EOL;
}

// 山田太郎
// 佐藤花子

著者が1人の場合も複数の場合も、同じようにforeachで処理できます。取得した値の前後に改行や空白が含まれる可能性があるため、表示や保存の前にtrim()で整えています。

名前空間付きの要素を取得する

今回の出版日は、meta:publishedという名前空間付きの要素です。名前空間付きの要素は、通常の$book->publishedでは取得できません。

SimpleXMLでは、名前空間URIを指定してchildren()を呼び出すと、その名前空間に属する子要素へアクセスできます。

$meta = $book->children('https://example.com/catalog/meta');

echo (string) $meta->published, PHP_EOL;
// 2026-09-01

XML内で使われているmetaという接頭辞ではなく、名前空間URIを指定している点に注目してください。XML側の接頭辞が別名に変わっても、同じURIであれば取得できます。

名前空間付きの属性を取得する場合は、attributes()へ名前空間URIを渡します。今回のサンプルでは使っていませんが、要素と属性で同じ考え方を使えます。

XPathで対象の要素を検索する

要素を順番にたどるだけでなく、条件に合う要素をまとめて検索したい場合はxpath()を使います。例えば、category属性がtechnicalの書籍だけを取得するには、次のようにします。

$technicalBooks = $xml->xpath(
    '/catalog/book[@category="technical"]'
);

if ($technicalBooks === false || $technicalBooks === null) {
    throw new RuntimeException('XPathの実行に失敗しました。');
}

foreach ($technicalBooks as $book) {
    echo (string) $book->title, PHP_EOL;
}

// PHPでWeb APIを呼び出す

xpath()は、成功すると検索結果の配列を返します。該当する要素がない場合は空の配列になるため、検索に失敗した場合と区別できます。

XPathで名前空間付きの要素を検索する場合は、先にregisterXPathNamespace()でXPath用の接頭辞を登録します。

$xml->registerXPathNamespace(
    'meta',
    'https://example.com/catalog/meta'
);

$publishedDates = $xml->xpath('/catalog/book/meta:published');

if ($publishedDates === false || $publishedDates === null) {
    throw new RuntimeException('XPathの実行に失敗しました。');
}

foreach ($publishedDates as $publishedDate) {
    echo (string) $publishedDate, PHP_EOL;
}

// 2026-09-01
// 2026-09-05

registerXPathNamespace()で登録するmetaは、XPath式の中で使うための名前です。XMLファイル内の接頭辞と同じである必要はなく、名前空間URIが一致していることが重要です。

XMLを配列へ変換する

SimpleXMLのオブジェクトをそのままアプリケーション全体へ渡すのではなく、必要な項目だけを配列へ変換しておくと、XMLの構造を呼び出し側で再解釈せずに済みます。

ここでは、必須項目のタイトルが空の書籍はスキップし、著者や出版日は空の場合にnullとして扱います。

function textOrNull(SimpleXMLElement $element): ?string
{
    $text = trim((string) $element);

    return $text !== '' ? $text : null;
}

$books = [];

foreach ($xml->book as $book) {
    $title = textOrNull($book->title);

    if ($title === null) {
        fwrite(STDERR, "タイトルがない書籍をスキップしました。" . PHP_EOL);
        continue;
    }

    $attributes = $book->attributes();
    $meta = $book->children('https://example.com/catalog/meta');
    $authors = [];

    foreach ($book->authors->author as $author) {
        $authorName = textOrNull($author);

        if ($authorName !== null) {
            $authors[] = $authorName;
        }
    }

    $books[] = [
        'id' => isset($attributes['id'])
            ? (string) $attributes['id']
            : null,
        'category' => isset($attributes['category'])
            ? (string) $attributes['category']
            : null,
        'title' => $title,
        'authors' => $authors,
        'publishedAt' => textOrNull($meta->published),
    ];
}

var_dump($books);

この処理では、XMLのbook要素から、アプリケーション側で必要なid、category、title、authors、publishedAtだけを取り出しています。XMLの要素名や名前空間の扱いは、この変換処理の中だけで済ませます。

XMLを読み込んで実行する

ここまでの処理をparse-catalog.phpへまとめます。まず、PHPのバージョンとSimpleXML、libxml拡張が有効になっていることを確認。

php -v
php -m | Select-String "SimpleXML|libxml"

スクリプトとcatalog.xmlを同じディレクトリへ保存したら、次のように実行します。

php parse-catalog.php

2件の書籍が配列へ変換され、id、title、authors、publishedAtなどが表示されれば、基本的な解析はできています。

解析できないXMLと該当データがない場合を分ける

XMLを扱う処理では、少なくとも次の状態を分けて考えます。

  • ファイルが存在しない、または読み込めない
  • XMLの構文が不正で解析に失敗した
  • 解析はできたが、対象の要素が存在しない
  • 要素は存在するが、値や属性が空になっている
  • XMLは解析できたが、文字コードが想定と異なる

例えば、XPathの検索結果が空の場合は、条件に一致するデータがないだけかもしれません。一方、xpath()がfalseやnullを返す場合は、XPath式や解析状態を確認する必要があります。

要素が存在しない場合に文字列へ変換すると空文字列になることがあるため、必須項目についてはまず空文字列かどうかを確認します。任意項目はnullへ変換しておくと、欠損と空文字列をアプリケーション側で扱いやすくなります。

文字コードを確認する

日本語を含むXMLでは、XML宣言に書かれた文字コード、実際のファイルの保存形式、処理環境の想定が一致しているかを確認します。

<?xml version="1.0" encoding="UTF-8"?>

例えば、UTF-8以外の文字コードで保存したファイルにUTF-8と記載すると、解析結果が文字化けしたり、解析に失敗したりする可能性があります。別の文字コードを扱う場合は、宣言を含めた変換方法を決め、変換後のXMLが正しい形式になっていることを確認する必要があります。

外部XMLを扱う場合の注意点

今回はローカルファイルを読み込みました。外部URLや利用者が指定したファイルを扱う場合は、XMLの解析以外にも確認することがあります。

利用者が指定したパスやURLをそのまま読み込まない

simplexml_load_file()へ利用者が指定したパスやURLをそのまま渡すと、意図しないローカルファイルや外部サーバーへアクセスする処理になる可能性があります。許可したディレクトリやホストだけを受け付け、リダイレクト先、取得サイズ、タイムアウトも確認する必要があります。

外部URLから取得する場合は、cURLなどで通信処理を分け、タイムアウトとレスポンスサイズを制限してから、取得した本文をsimplexml_load_string()へ渡す構成も検討すると良いでしょう。

外部エンティティやDTDの扱いに注意する

XMLのDTDや外部エンティティを使う必要がない場合は、外部参照を有効にするオプションを追加しないようにします。特にLIBXML_NOENTは、エンティティを置換するためのオプションですが、外部エンティティの取得につながる可能性があります。

PHPやlibxmlのバージョンによって利用できる安全対策が異なるため、対象環境の公式マニュアルを確認しましょう。今回のローカルファイルの例では、ネットワークアクセスを無効にするLIBXML_NONETを指定しています。

取得先の利用条件を確認する

外部サービスやWebサイトのXMLを定期的に取得する場合は、APIやデータ提供手段の有無、利用規約、アクセス頻度、キャッシュ、保存・再配布条件の確認が必要です。XMLを解析できることと、そのデータを自由に利用できることは別の問題です。

まとめ

PHPでXMLを扱うときは、SimpleXMLを使ってXMLをSimpleXMLElementへ読み込み、要素名によるアクセス、attributes()による属性取得、foreachによる繰り返し要素の処理を行えます。

名前空間付きの要素は、名前空間URIを指定したchildren()や、registerXPathNamespace()で接頭辞を登録したxpath()で取得します。XMLを読み込めたことと、必要な要素や値が存在することは分けて確認します。

外部XMLを扱う場合は、利用者が指定したパスやURLをそのまま読み込まず、ネットワークアクセス、外部エンティティ、タイムアウト、取得サイズ、利用条件まで含めて設計することが大切です。

参考資料

この記事を書いた人

※上が私です。

奈良市を拠点に、27年以上の経験を持つフリーランスWebエンジニア、阿部辰也です。

これまで、ECサイトのバックエンド開発や業務効率化システム、公共施設の予約システムなど、多彩なプロジェクトを手がけ、企業様や制作会社様のパートナーとして信頼を築いてまいりました。

【制作会社・企業様向けサポート】
  • 専任エンジニアのいない企業様に対するシステム面の不安を解消
  • 柔軟な契約形態や短納期での対応により、急なニーズにも迅速にサポート
  • システムの企画段階から運用まで、ワンストップでのサービスを提供

Webシステムの開発やサイト改善でお困りの際は、どうぞお気軽にご相談ください。小さな疑問から大規模プロジェクトまで、最適なご提案を心を込めてさせていただきます。

ぜひ、プロフィールやWeb制作会社様向け業務案内、一般企業様向け業務案内もご覧くださいね。

Laravelのコードレビューで遅いSQLの候補を洗い出す

2026.10.02

Laravelのコードレビューで、ループ内のDBアクセスやEloquentのN+1、大量取得、検索条件とインデックスなど、性能問題につながりやすい箇所を候補として洗い出します。Laravelで発行SQLと実行時間を確認し、MySQLのEXPLAINや実データに近い環境での計測へつなげる方法を紹介します。コードレビューだけではSQLの実行時間を断定できない点も説明します。

Laravel MySQL PHP

Windows 11でDocker Composeを使ってLaravel環境を作る:Container・Volume・Networkの基本

2026.10.01

Windows 11のDocker Desktop上に、DockerfileとDocker Composeを使ってLaravel・PHP・MySQL・Mailpitの開発環境を構築します。ImageとContainerの関係、Bind MountとNamed Volumeによるデータの保存、ポート公開とContainer間通信の違いを実例で確認。LaravelからMySQLへ接続するときに、localhostではなくService名を使う理由も説明します。

Docker Laravel PHP

PHPでYAML設定を検証する:symfony/yamlとopis/json-schemaの使い方

2026.09.30

symfony/yamlでYAMLを読み込み、opis/json-schemaで必須項目や型、許可する値を検証する方法を紹介します。YAMLのマップをstdClassとして扱う方法や、空のobjectとarrayの違い、信頼できないYAMLを扱う際の注意点も解説します。

PHP YAML

PHPの正規表現で日本語・改行を扱う:u・m・s修飾子の違い

2026.09.29

PHPの正規表現で日本語や複数行テキストを扱う際の、u・m・s修飾子の違いを解説します。Unicode文字クラスと全角数字、CRLFの行末処理、\A・\zの使い方、Unicode正規化との違いを、PHP 8.3.15・PCRE2 10.42で確認したコード例とともに紹介します。

PHP 正規表現

阿部辰也へのお仕事の依頼・お問い合わせ

軽いご相談もお気軽にどうぞ!

個人情報の取り扱いについて *必須 プライバシーポリシーをご確認いただき、同意いただける場合は「同意する」にチェックをしてください。

keyboard_double_arrow_up
TOP