使用SimpleXML和xpath访问XML节点值

时间:2015-07-08 16:40:25

标签: php xml simplexml

有很多这些问题,请原谅我。我已经全部阅读过了。

我使用命名空间http://www.columbasystems.com/cpng/xmlviewer/cal/1-0/http://events.manchester.ac.uk/f3vf/calendar/tag:manchester_museum/view:list/p:q_details/calml.xml

获得以下XML文档

我尝试使用SimpleXML解析此文档。下面的示例代码是尝试访问标题节点" Discovery Center"从下面。

<ns:calendar xmlns:ns="http://www.columbasystems.com/cpng/xmlviewer/cal/1-0/">
    <ns:listView>
    <ns:day date="2015-07-08" weekDay="Wed">
    <ns:event>
    <ns:id xmlns:even="http://www.columbasystems.com/customers/uom/gpp/eventid/" query="{http://www.columbasystems.com/customers/uom/gpp/eventid/}b9v-ib270yqf-nmn54k">even:b9v-ib270yqf-nmn54k</ns:id>
    <ns:title>Discovery Centre</ns:title>
    ...
</ns:event>
</ns:day>
</ns:listView>
</ns:calendar>

PHP:

$feed_uri = 'http://events.manchester.ac.uk/f3vf/calendar/tag:manchester_museum/view:list/p:q_details/calml.xml';
$xml = simplexml_load_file($feed_uri);
$xml->registerXPathNamespace("ns", "http://www.columbasystems.com/cpng/xmlviewer/cal/1-0/");

foreach($xml->xpath('//ns:calendar/ns:listView/ns:day') as $day) {
    $events = $day->xpath('//ns:event');
    foreach($events as $event) {
        var_export($event->xpath('//ns:title'));
    }
}

输出几个空数组:

array ( 0 => SimpleXMLElement::__set_state(array( )),

我认为我使用xpath错误,我如何获得这些节点的值?

2 个答案:

答案 0 :(得分:4)

您的输出不是空数组。空数组如下所示:

array()

但你有这个:

array ( 0 => SimpleXMLElement::__set_state(array( )),

所以,显然XPath正在工作,并给你一个结果列表(数组)(SimpleXMLElement对象)。

问题在于var_export并不擅长检查SimpleXMLElement对象,因此您无法看到实际得到的结果。

要获取节点的文本内容,您必须将其强制转换为字符串 - 明确地使用(string)$node,或者隐式使用echo之类的内容。所以下面的内容可行:

foreach($xml->xpath('//ns:calendar/ns:listView/ns:day') as $day) {
    $events = $day->xpath('//ns:event');
    foreach($events as $event) {
        foreach ($event->xpath('//ns:title') as $title ) {
            echo $title;
        }
    }
}

但是,您的XPath表达式中确实存在一个小错误(与您使用SimpleXML或任何其他API无关)://前缀始终从文档的根开始,而不是用作的元素上下文。搜索&#34;当前元素中的任何深度&#34;您需要.//,例如$day->xpath('.//ns:event')

那就是说,你根本不需要像XPath这样的任何东西,因为它并不是那么深的结构。因此,只要您首先使用SimpleXML's normal access methods选择正确的命名空间,就可以使用the ->children() method

$cal_items = $xml->children("http://www.columbasystems.com/cpng/xmlviewer/cal/1-0/");

foreach($cal_items->listView->day as $day) {
    foreach($day->event as $event) {
        echo $event->title;
    }
}

请注意,您的XML包含没有名称空间前缀的属性,如<ns:day date="2015-07-09" weekDay="Thu">;有点不直观,这些是officially in no namespace at all,所以你必须切换回null命名空间来访问它们:

echo $day->attributes(null)['date'];

答案 1 :(得分:2)

我将xml放在字符串中,然后更改回文件。我希望,其他很明显

$str = '<ns:calendar xmlns:ns="http://www.columbasystems.com/cpng/xmlviewer/cal/1-0/">
    <ns:listView>
    <ns:day date="2015-07-08" weekDay="Wed">
    <ns:event>
    <ns:id xmlns:even="http://www.columbasystems.com/customers/uom/gpp/eventid/" query="{http://www.columbasystems.com/customers/uom/gpp/eventid/}b9v-ib270yqf-nmn54k">even:b9v-ib270yqf-nmn54k</ns:id>
    <ns:title>Discovery Centre</ns:title>
</ns:event>
</ns:day>
</ns:listView>
</ns:calendar>';

$xml = simplexml_load_string($str);
$xml->registerXPathNamespace("ns", "http://www.columbasystems.com/cpng/xmlviewer/cal/1-0/");

foreach($xml->xpath('//ns:calendar/ns:listView/ns:day') as $day) {
    echo $day['date'] . ' ';
    $events = $day->xpath('.//ns:event');
    foreach($events as $event) {
        echo $event->xpath('.//ns:title/text()')[0];

    }
}

结果

2015-07-08 Discovery Centre

<强>更新 您可以使用前缀insead完整网址。并记住在这种情况下如何获得属性值

$cal_items = $xml->children("ns",true);
foreach($cal_items->listView->day as $day) {
    echo $day->attributes()['date'] . ' ' ;
    foreach($day->event as $event) {
        echo $event->title;
    }
}