Intereting Posts

PHP Анализ XML-ответа со многими пространствами имен

Есть ли способ проанализировать XML-ответ в PHP, учитывая все узлы с именами и преобразовать их в объект или массив, не зная всех имен узлов?

Например, преобразование:

<?xml version="1.0" encoding="ISO-8859-1"?> <serv:message xmlns:serv="http://www.webex.com/schemas/2002/06/service" xmlns:com="http://www.webex.com/schemas/2002/06/common" xmlns:att="http://www.webex.com/schemas/2002/06/service/attendee"> <serv:header> <serv:response> <serv:result>SUCCESS</serv:result> <serv:gsbStatus>PRIMARY</serv:gsbStatus> </serv:response> </serv:header> <serv:body> <serv:bodyContent xsi:type="att:lstMeetingAttendeeResponse" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"> <att:attendee> <att:person> <com:name>James Kirk</com:name> <com:firstName>James</com:firstName> <com:lastName>Kirk</com:lastName> <com:address> <com:addressType>PERSONAL</com:addressType> </com:address> <com:phones /> <com:email>Jkirk@sz.webex.com</com:email> <com:type>VISITOR</com:type> </att:person> <att:contactID>28410622</att:contactID> <att:joinStatus>INVITE</att:joinStatus> <att:meetingKey>803754412</att:meetingKey> </att:attendee> </serv:bodyContent> </serv:body> </serv:message> 

к чему-то вроде:

 ['message' => [ 'header' => [ 'response' => [ 'result' => 'SUCCESS', 'gsbStatus' => 'PRIMARY' ] ], 'body' => [ 'bodyContent' => [ 'attendee' => [ 'person' => [ 'name' => 'James Kirk', 'firstName' => 'James', ... ], 'contactID' => 28410622, ... ] ] ] ] 

Я знаю, что это легко с узлами, не поддерживающими имена, но я не знаю, с чего начать что-то подобное.

(Прочитайте @ ThW ответ о том, почему массив на самом деле не так важно, чтобы стремиться)

Я знаю, что это легко с узлами, не поддерживающими имена, но я не знаю, с чего начать что-то подобное.

Это так же просто, как с узлами с именами, потому что технически они одинаковы. Давайте дадим краткий пример: следующий скрипт перебирает все элементы документа независимо от пространства имен:

 $result = $xml->xpath('//*'); foreach ($result as $element) { $depth = count($element->xpath('./ancestor::*')); $indent = str_repeat(' ', $depth); printf("%s %s\n", $indent, $element->getName()); } 

Вывод в вашем случае:

  message header response result gsbStatus body bodyContent attendee person name firstName lastName address addressType phones email type contactID joinStatus meetingKey 

Как вы можете видеть, вы можете выполнять итерацию по всем элементам, как если бы у них вообще не было пространства имен.

Но, как было указано, когда вы игнорируете пространство имен, вы также потеряете важную информацию. Например, с документом, который у вас есть, вы действительно заинтересованы в посетителе и общих элементах, элементы обслуживания касаются транспорта:

 $uriAtt = 'http://www.webex.com/schemas/2002/06/service/attendee'; $xml->registerXPathNamespace('att', $uriAtt); $uriCom = 'http://www.webex.com/schemas/2002/06/common'; $xml->registerXPathNamespace('com', $uriCom); $result = $xml->xpath('//att:*|//com:*'); foreach ($result as $element) { $depth = count($element->xpath("./ancestor::*[namespace-uri(.) = '$uriAtt' or namespace-uri(.) = '$uriCom']")); $indent = str_repeat(' ', $depth); printf("%s %s\n", $indent, $element->getName()); } 

Примерный результат на этот раз:

  attendee person name firstName lastName address addressType phones email type contactID joinStatus meetingKey 

Так зачем же бросать все пространства имен? Они помогут вам получить интересующие вас элементы. Вы также можете делать это динамически

Разве мы не имеем общего преобразования в массив. Просто загрузите и прочитайте. Это не так сложно, если вы используете DOM + XPath.

Общее преобразование означает, что вы теряете информацию (пространства имен) и функциональность (XPath).

Сначала создайте DOM и загрузите XML:

 $dom = new DOMDocument(); $dom->loadXml($xml); 

Теперь создайте экземпляр DOMXPath для DOM и зарегистрируйте префиксы для пространств имен. Это могут быть префиксы из документа XML или разные.

 $xpath = new DOMXPath($dom); $xpath->registerNamespace('serv', 'http://www.webex.com/schemas/2002/06/service'); $xpath->registerNamespace('com', 'http://www.webex.com/schemas/2002/06/common'); $xpath->registerNamespace('att', 'http://www.webex.com/schemas/2002/06/service/attendee'); 

Используйте зарегистрированные префиксы в выражении XPath для извлечения значений и узлов:

 var_dump( $xpath->evaluate('string(/serv:message/serv:header/serv:response/serv:result)') ); 

Вывод:

 string(7) "SUCCESS" 

Извлеките все элементы attendee и выведите имена:

 foreach ($xpath->evaluate('/serv:message/serv:body/serv:bodyContent/att:attendee') as $attendee) { var_dump( $xpath->evaluate('string(att:person/com:name)', $attendee) ); }; 

Вывод:

 string(10) "James Kirk"