使用SimpleXML解析带有名称空间的XML

时间:2011-08-25 13:00:14

标签: php xml parsing simplexml

我试图找出使用SimpleXML解析相当复杂的XML的最有效方法,并且当文档中存在名称空间时我就陷入困境。

好的,所以我的XML看起来像这样:

<ns:event xmls:ns="http://example.com/event/1.1">
   <ns:eventinfo>
       <ns:start year="2011" month="9" />
       <ns:eventnames>
           <ns:eventname>Superevent</ns:eventname>
       </ns:eventnames>
   </ns:eventinfo>
   <ns:eventlocale>My place</ns:eventlocale>
</ns:event> 

我可以通过以下方式从“普通”标签中提取信息:

$data = simplexml_load_string($xml);
foreach ($data->children('ns', true) as $children) {
    $child = $children->children('ns',true);
    $eventname = ($child->eventname);
}

这会将$ eventname作为Superevent。但是,这种方法不适用于属性......

但如果没有任何名称空间,我会轻易地提取属性,例如:

$startyear = $data->$start['year'];

那么 - 任何人都有想法轻松解决这个问题?任何信息或想法将不胜感激。

4 个答案:

答案 0 :(得分:1)

您是否考虑过使用SimpleXML's xpath功能?

// your data example missed an 'n' in xmlns, so reposted, just to be sure
// with some additional ns:event elements in a root element
$xml = '<?xml version="1.0" encoding="utf-8"?>
<root>
    <ns:event xmlns:ns="http://example.com/event/1.1">
       <ns:eventinfo>
           <ns:start year="2011" month="9" />
           <ns:eventnames>
               <ns:eventname>Superevent</ns:eventname>
           </ns:eventnames>
       </ns:eventinfo>
       <ns:eventlocale>My place</ns:eventlocale>
    </ns:event>
    <ns:event xmlns:ns="http://example.com/event/1.1">
       <ns:eventinfo>
           <ns:start year="2011" month="8" />
           <ns:eventnames>
               <ns:eventname>Another Superevent</ns:eventname>
           </ns:eventnames>
       </ns:eventinfo>
       <ns:eventlocale>Your place</ns:eventlocale>
    </ns:event>
</root>';

$data = simplexml_load_string($xml);
$data->registerXPathNamespace( 'ns', 'http://example.com/event/1.1' );

# '//ns:event' means: find ns:event elements anywhere in the document
# '/ns:event' would mean: find ns:event elements that are direct children of the root
$events = $data->xpath( '//ns:event' );
foreach( $events as $event )
{

    # from now on, we are using $event (ns:event elements) as our contexts to query

    # '.' means: from our current context node find...
    # '/ns:eventinfo[1]' means: find the first ns:eventinfo element that is a direct child of the preceding expression
    # '/ns:eventnames[1]' means: same as previous but ns:eventnames element
    # '/ns:eventname[1]' means: same as previous but ns:eventname element
    $eventname   = $event->xpath( './ns:eventinfo[1]/ns:eventnames[1]/ns:eventname[1]' );

    # '/@year' means: the year attribute that is a direct child of the preceding expression
    $year        = $event->xpath( './ns:eventinfo[1]/ns:start[1]/@year' );

    # '/@month' means: same as previous but month attribute
    $month       = $event->xpath( './ns:eventinfo[1]/ns:start[1]/@month' );

    $eventlocale = $event->xpath( './ns:eventlocale[1]' );

    # echo the first elements from the results found by our xpath queries
    echo 'Event "' . $eventname[ 0 ] . '" taking place at ' . $eventlocale[ 0 ] . ' sometime in ' . $month[ 0 ] . '/' . $year[ 0 ] . '<br>';
}

修改

我在上一个例子中所做的事情是相当冗长的。这应该可以在循环内部工作,因为您已经在echo语句中已经找到了第一个找到的节点:

# relative to our context node '.' find all descendants '//' that is an ns:eventname element
$eventname   = $event->xpath( './/ns:eventname' );
# relative to our context node '.' find all descendants '//' that is a year attribute of an ns:start element
$year        = $event->xpath( './/ns:start/@year' );
# relative to our context node '.' find all descendants '//' that is a month attribute of an ns:start element
$month       = $event->xpath( './/ns:start/@month' );
# relative to our context node '.' find all children '/' that is an ns:eventlocale element
$eventlocale = $event->xpath( './ns:eventlocale' );

答案 1 :(得分:0)

您可以使用类似于使用simplexml_load_string之前的内容:

$xml = preg_replace("/(<\/?)(\w+):([^>]*>)/", "$1$2$3", $xml);

有关替换参数(“$ 1 $ 2 $ 3”)的说明,请参阅http://php.net/manual/en/function.preg-replace.php

这会将<ns:eventinfo>更改为<nseventinfo>

答案 2 :(得分:0)

在您的示例中,不应该是$children->start['year']而不是$data->start['year']

这是一个工作的例子:

http://codepad.org/8i0fHYdo

答案 3 :(得分:0)

您可以按代码访问eventname:

$data->children("http://example.com/event/1.1")->eventinfo->children("http://example.com/event/1.1")->eventnames->children("http://example.com/event/1.1")->eventname

有关如何使用子级和使用命名空间解析XML的更多详细信息,请参阅我的帖子Parse XML with namespace by SimpleXML in PHP。 XML是从Salesforce输出消息生成的,其中包含XML命名空间。我使用SimpleXML在children()的帮助下解析它。