class ConvertXml{ // .... }
ログイン後にコピー
class ConvertXml{ public function xmlToArray(SimpleXMLIterator $xml): array { $res = []; for ($xml->rewind(); $xml->valid(); $xml->next()) { $a = []; if (!array_key_exists($xml->key(), $a)) { $a[$xml->key()] = []; } if ($xml->hasChildren()) { $a[$xml->key()][] = $this->xmlToArray($xml->current()); } else { $a[$xml->key()] = (array) $xml->current()->attributes(); $a[$xml->key()]['value'] = strval($xml->current()); } $res[] = $a; } return $res; } // ..... } $wsdl = 'http://flash.weather.com.cn/wmaps/xml/china.xml'; $xml = new SimpleXMLIterator($wsdl, 0, true); $convert = new ConvertXml(); // var_dump($convert->xmlToArray($xml)); // array(37) { // [0]=> // array(1) { // ["city"]=> // array(2) { // ["@attributes"]=> // array(9) { // ["quName"]=> // string(9) "黑龙江" // ["pyName"]=> // string(12) "heilongjiang" // ["cityname"]=> // string(9) "哈尔滨" // ["state1"]=> // string(1) "7" // ["state2"]=> // string(1) "3" // ["stateDetailed"]=> // string(15) "小雨转阵雨" // ["tem1"]=> // string(2) "21" // ["tem2"]=> // string(2) "16" // ["windState"]=> // string(21) "南风6-7级转4-5级" // } // ["value"]=> // string(0) "" // } // } // [1]=> // array(1) { // ["city"]=> // array(2) {
ログイン後にコピー
ここでは、SimpleXMLIterator オブジェクトを使用しています。名前からわかるように、その役割は、走査可能な SimpleXMLElement オブジェクトを生成することです。最初のパラメータは、適切にフォーマットされた XML テキストまたはリンク アドレスです。 2 番目のパラメータはいくつかのオプションパラメータですが、ここでは直接 0 を与えるだけで済みます。 3 番目のパラメータは、最初のパラメータがリンク アドレスであるかどうかを示します。ここでは true を指定します。
クライアント側で SimpleXMLIterator オブジェクトを生成し、それを xmlToArray() メソッドに渡しました。このように、SimpleXMLIterator オブジェクトを使用すると、各ノードをトラバースできます。次の作業は非常に簡単です。ノードに子ノードがあるかどうかを確認するだけです。子ノードがある場合は、現在のメソッドを再帰的に呼び出します。子ノードがない場合は、ノードの属性とコンテンツを取得します。
このテスト リンクは、気象情報を取得するためのものです。返されたコンテンツの各ノードには属性のみがあり、コンテンツはありません。これは、値フィールドが空の変換された配列に反映されます。
PHP 配列またはオブジェクトを XML に変換
class ConvertXml{ public function xmlToArray(SimpleXMLIterator $xml): array { $res = []; for ($xml->rewind(); $xml->valid(); $xml->next()) { $a = []; if (!array_key_exists($xml->key(), $a)) { $a[$xml->key()] = []; } if ($xml->hasChildren()) { $a[$xml->key()][] = $this->xmlToArray($xml->current()); } else { $a[$xml->key()] = (array) $xml->current()->attributes(); $a[$xml->key()]['value'] = strval($xml->current()); } $res[] = $a; } return $res; } // ..... } $wsdl = 'http://flash.weather.com.cn/wmaps/xml/china.xml'; $xml = new SimpleXMLIterator($wsdl, 0, true); $convert = new ConvertXml(); // var_dump($convert->xmlToArray($xml)); // array(37) { // [0]=> // array(1) { // ["city"]=> // array(2) { // ["@attributes"]=> // array(9) { // ["quName"]=> // string(9) "黑龙江" // ["pyName"]=> // string(12) "heilongjiang" // ["cityname"]=> // string(9) "哈尔滨" // ["state1"]=> // string(1) "7" // ["state2"]=> // string(1) "3" // ["stateDetailed"]=> // string(15) "小雨转阵雨" // ["tem1"]=> // string(2) "21" // ["tem2"]=> // string(2) "16" // ["windState"]=> // string(21) "南风6-7级转4-5级" // } // ["value"]=> // string(0) "" // } // } // [1]=> // array(1) { // ["city"]=> // array(2) {
ログイン後にコピー
class ConvertXml{ // ...... const UNKNOWN_KEY = 'unknow'; public function arrayToXml(array $a) { $xml = new SimpleXMLElement(' '); $this->phpToXml($a, $xml); return $xml->asXML(); } protected function phpToXml($value, &$xml) { $node = $value; if (is_object($node)) { $node = get_object_vars($node); } if (is_array($node)) { foreach ($node as $k => $v) { if (is_numeric($k)) { $k = 'number' . $k; } if (!is_array($v) && !is_object($v)) { $xml->addChild($k, $v); } else { $newNode = $xml->addChild($k); $this->phpToXml($v, $newNode); } } } else { $xml->addChild(self::UNKNOWN_KEY, $node); } } } var_dump($convert->arrayToXml($data)); // string(84454) " // ........... // "
ログイン後にコピー
arrayToXml() では、まず SimpleXMLElement オブジェクトを使用して基本的なルート ノード構造を作成しました。次に、phpToXml() メソッドを使用してすべてのノードを作成します。なぜ 2 つの方法に分けるのでしょうか? phpToXml() メソッドは再帰的に呼び出す必要があるため、再帰のたびにルート ノードを再作成する必要はなく、ルート ノードの下で addChild() を使用して子ノードを追加するだけで済みます。
phpToXml() のコードでは、get_object_vars() 関数も使用します。つまり、渡された配列項目の内容がオブジェクトの場合、この関数を通じてオブジェクトのすべてのプロパティを取得できます。オブジェクトを配列と考えると、各属性値はそのキーと値のペアになります。
各キー値を走査するときに、現在のキーに対応するコンテンツが配列であるかオブジェクトであるかを判断します。コンテンツがこれら 2 つの形式ではない場合、現在のコンテンツは現在のノードの子ノードとして直接追加されます。配列またはオブジェクトの場合は、配列の内容がすべて調べられるまで再帰的に追加を続けます。
テストの $data コンテンツは非常に長いため、テスト コードへのリンクを通じて Github で直接確認できます。
概要
この記事の内容は、SPL 拡張ライブラリでの XML 操作のための 2 つのオブジェクトの使用法を学ぶことです。これらを介して、XML データ形式を簡単に変換できます。もちろん、XML フォーマット変換には他の方法もあります。これについては後ほど説明します。
テスト コード:
https://github.com/zhangyue0503/dev-blog/blob/master/php/202009/source/PHP 変換で SPL ライブラリのオブジェクト メソッドを使用するXML と array.php
class ConvertXml{ // ...... const UNKNOWN_KEY = 'unknow'; public function arrayToXml(array $a) { $xml = new SimpleXMLElement(''); $this->phpToXml($a, $xml); return $xml->asXML(); } protected function phpToXml($value, &$xml) { $node = $value; if (is_object($node)) { $node = get_object_vars($node); } if (is_array($node)) { foreach ($node as $k => $v) { if (is_numeric($k)) { $k = 'number' . $k; } if (!is_array($v) && !is_object($v)) { $xml->addChild($k, $v); } else { $newNode = $xml->addChild($k); $this->phpToXml($v, $newNode); } } } else { $xml->addChild(self::UNKNOWN_KEY, $node); } } } var_dump($convert->arrayToXml($data)); // string(84454) " // ........... // "
ログイン後にコピー