PHP解析具有许多名称空间的XML响应

时间:2015-04-01 14:55:18

标签: php xml parsing simplexml xml-namespaces

有没有办法在PHP中解析XML响应,考虑所有命名空间节点并将其转换为对象或数组而不知道所有节点名称?

例如,转换它:

<?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,
                ...
            ]
        ]
    ]
]

我知道非命名空间节点很容易,但我不知道从哪里开始这样的事情。

2 个答案:

答案 0 :(得分:3)

(阅读@ 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

那么为什么要删除所有命名空间?它们可以帮助您获得您感兴趣的元素。您也可以动态地执行它。

答案 1 :(得分:2)

请不要将通用转换为数组。只需加载并阅读它。如果你使用DOM + XPath并不困难。

通用转换意味着您丢失了信息(命名空间)和功能(XPath)。

首先创建一个DOM并加载XML:

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

现在为DOM创建DOMXPath实例并为命名空间注册前缀。这可以是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"