XMLをPHPでパース

2種類のパース方法

simplexml_load_file()

  • 特徴: シンプルな記述で、階層構造の要素や値をすぐ取得できる。
  • 向いているケース:
    • 階層が深くても、要素名が分かっていて直接アクセスしたい場合。
    • XPathも使えるが、複雑な操作や属性の細かい制御はやや苦手。

DOMDocument

  • 特徴: XMLのノードを細かく操作できる。属性や名前空間、ノードの追加・削除なども柔軟。
  • 向いているケース:
    • 名前空間や属性の扱いが多い場合。
    • ノードの追加・削除・編集など、XML構造自体を変更したい場合。
    • 複雑なXPathや詳細な検索が必要な場合。

結論
値の取得や簡単な検索なら simplexml_load_file() が手軽でおすすめ
XMLの編集や複雑な検索・名前空間の厳密な扱いが必要なら DOMDocument が向いています
階層が深いだけなら、まずは simplexml_load_file

XMLをSimpleXMLElementでパース後

要素までの呼び方

目的の項目までの指定方法は、一般的に「パス(path)」や「階層(hierarchy)」と呼ばれる
XMLの場合:「ノードパス」「XMLパス」「階層」などと呼ばれます。XPath(エックスパス)という正式なパス指定方法もあります。
JSONの場合:「パス」「プロパティパス」「キーの階層」などと呼ばれます。JSONPath(ジェイソンパス)というパス指定方法もあります。

2種類のパース、中身

どちらの方法でも**最終的に $obj は同じ型(SimpleXMLElementオブジェクト)**になります。

XPath

目的の要素を簡単に検索するためのメソッドとして XPath を使うことができます。
たとえば、$obj->xpath(‘パス’) で目的の要素を配列で取得できます。
xpath() メソッドは SimpleXMLElement オブジェクトで利用できます。

XPathの . の有無

ドット(.)が付く場合:.//m:Kind

  • 現在のノード(コンテキストノード)から相対的に検索
  • $item->xpath('.//m:Kind') の場合、$item 要素の子孫要素の中からKindを探す

ドット(.)が付かない場合://m:Kind

  • XMLドキュメント全体から検索
  • ルート要素から全てのKind要素を探す

具体例

複数要素の一括指定

取得できないパターン

構造上の問題

  1. TimeDefine と Kind は別々の階層にある
    • TimeDefine は時間定義用の要素
    • Kind はデータ種別を示す要素
    • この2つを // で直接つなげることはできません
  2. 正しい階層構造

属性付き要素の指定

refID=”1″ のような属性を持つ要素をXPathで指定する場合、以下のように書きます。

すべての WaveHeightForecastPart 要素のうち、refID 属性が “1” のものを取得します。
このように、[@属性名=”値”] で属性値を指定できます。

名前空間

XMLに名前空間(xmlns属性)がある場合、SimpleXMLElementのxpathはそのままでは要素を見つけられません。

<Report xmlns=”http://xml.kishou.go.jp/jmaxml1/” xmlns:jmx=”http://xml.kishou.go.jp/jmaxml1/” xmlns:jmx_add=”http://xml.kishou.go.jp/jmaxml1/addition1/”>

この xmlns や xmlns:○○ で始まる属性が「名前空間(namespace)」を定義している部分です。
xmlns=”…” はデフォルト名前空間
xmlns:jmx=”…” や xmlns:jmx_add=”…” はプレフィックス付き名前空間
この名前空間があると、XPathで要素を検索する際に特別な指定が必要になります。

foreach時の新しいオブジェクトについて

foreach でSimpleXMLElementを回すたびに、新しいSimpleXMLElementオブジェクトが作られるため、元のオブジェクトに登録した名前空間が引き継がれません。そのため毎回 registerXPathNamespace() が必要になります。

要素値がわかっている場合のパスの取得例

この関数は、最初に与えた要素(例:$obj->Body)から再帰的に探索します。
完全なXPath(ルートからのパス)を取得したい場合は、$obj から再帰的にたどる必要があります。
属性値や複数同名要素がある場合は、さらに工夫が必要です。

要素値がわかっている場合のパスの取得例(複数条件)

例:【12時から18時まで】の【内陸】の【降水確率】を取得したい場合

XMLの構造を動的に見たい時は下みたいなスニペットが役立ちます👇

これで階層構造がざっくり俯瞰できるので、XPathを設計するときにかなり助かります。

「要素のテキスト値も出すバージョン」

親の要素を取得する

方法1: XPathのparent::軸を使用

方法2: XPathのancestor::軸を使用(上位の祖先要素も取得)

方法3: 最初から親要素を含めて取得

方法4: 段階的に親をたどる

コメント

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