Есть ли способ проанализировать 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>[email protected]</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"