使用SimpleXMLparser php解析带有名称空间的xml

时间:2014-06-07 18:05:34

标签: php xml simplexml

我正在尝试解析这样的XML:

<?xml version="1.0" encoding="UTF-8"?>
<gml:FeatureCollection 
    xmlns:ogc="http://www.opengis.net/ogc" 
    xmlns:gml="http://www.opengis.net/gml"
    xmlns:xlink="http://www.w3.org/1999/xlink" 
    xmlns:wfs="http://www.opengis.net/wfs"
    xmlns:p="http://example.org">
    <gml:featureMember>
        <p:Point>
            <gml:pointProperty>
                <gml:Point srsName="epsg:4258">
                    <gml:pos>-3.84307585 43.46031547</gml:pos>
                </gml:Point>
                <gml:Point srsName="epsg:4258">
                    <gml:pos>-3.84299411 43.46018513</gml:pos>
                </gml:Point>
                <gml:Point srsName="epsg:4258">
                    <gml:pos>-3.84299935 43.45998723</gml:pos>
                </gml:Point>
                <!-- 
                    ... many more <gml:Point> nodes ...
                --> 
                <gml:Point srsName="epsg:4258">
                    <gml:pos>-3.84309913 43.46054546</gml:pos>
                </gml:Point>
                <gml:Point srsName="epsg:4258">
                    <gml:pos>-3.84307585 43.46031547</gml:pos>
                </gml:Point>
            </gml:pointProperty>
        </p:Point>
    </gml:featureMember>
</gml:FeatureCollection>

我希望将每个gml:pos行保存到数据库中,但目前我很乐意在网络空间中打印它们(echo ...)

$output = simplexml_load_string($output);
$xml = $output->getNamespaces(true); 
//print_r( $xml);
$xml_document = $output->children($xml["p"]);
foreach($xml_document->Point->children($xml["gml"]);
    echo $xml_point->Point[0];
echo $xml->FeatureCollection; 
}

$ output 中,gml:point

中有完整的xml,坐标吨数

但是我试图使用命名空间来达到要点,但我必须做错事,因为除了数组字之外我不能打印任何东西(即使使用print_r ...)

2 个答案:

答案 0 :(得分:2)

您不应该从文档中读取命名空间。命名空间是一个唯一的字符串,用于定义标记所属的XML语义。您的XML就是一个很好的例子,因为它在两个不同的命名空间中有Point个元素。

p:Point是{http://example.org}:点 gml:Point是{http://www.opengis.net/gml}:点

pgml这样的名称空间前缀是别名,可以使文档更小,更易读。它们仅对元素及其子元素有效。它们可以在任何时候重新定义。更重要的是,它们仅对文档有效。

因此,要读取XML,您可以为命名空间定义自己的前缀,并将它们与Xpath一起使用,或者使用DOM方法的名称空间感知变体,如getAttributeNS()。 Xpath是一个很好的解决方案。您可以使用文档中的前缀或不同的前缀。

$element = simplexml_load_string($content);
$element->registerXPathNamespace('gml', 'http://www.opengis.net/gml');
$element->registerXPathNamespace('p', 'http://example.org');

$result = [];
$positions = $element->xpath('//p:Point[1]//gml:pos');
foreach ($positions as $pos) {
  $result[] = (string)$pos;
}

var_dump($result);

输出:https://eval.in/159739

array(5) {
  [0]=>
  string(23) "-3.84307585 43.46031547"
  [1]=>
  string(23) "-3.84299411 43.46018513"
  [2]=>
  string(23) "-3.84299935 43.45998723"
  [3]=>
  string(23) "-3.84309913 43.46054546"
  [4]=>
  string(23) "-3.84307585 43.46031547"
}

答案 1 :(得分:0)

使用XPath会更容易,因为您的节点深度嵌套在交替的命名空间中,但由于您使用的是 SimpleXML ,我将向您展示使用该框架的解决方案。

$output->children($xml["p"]);

因为根节点在p命名空间中没有 children 而无法工作。您必须在树中导航,直到您处于正确的上下文中。使用XPath,您可以使用descendant轴表达式获取它们,这将更简单。以下代码适用于 SimpleXML

$pointProperty = $output
                 ->children($xml["gml"])->featureMember
                 ->children($xml["p"])->Point
                 ->children($xml["gml"]);

现在,您可以循环pointProperty孩子,您将获得Point个节点:

foreach($pointProperty->children($xml["gml"]) as $point)
    print_r($point);

从那时起,名称空间不会发生变化,因此您可以正常导航并获取pos元素中的数据。这是一个例子:

echo '<table border="1">'."\n";
echo '  <tr><th>srsName</th><th>Longitude</th><th>Latitude</th></tr>'."\n";
foreach($pointProperty->children($xml["gml"]) as $point) {
    $coords = explode (' ', $point->pos);
    echo '  <tr><td>'.$point->attributes()['srsName'].'</td>';
    echo '<td>'.$coords[0].'</td>';
    echo '<td>'.$coords[1].'</td></tr>'."\n";
}
echo '</table>'."\n";

这将打印包含您的数据的表格。您可以根据自己的需要进行调整:

<table border="1">
  <tr><th>srsName</th><th>Longitude</th><th>Latitude</th></tr>
  <tr><td>epsg:4258</td><td>-3.84307585</td><td>43.46031547</td></tr>
  <tr><td>epsg:4258</td><td>-3.84299411</td><td>43.46018513</td></tr>
  ...
  <tr><td>epsg:4258</td><td>-3.84307585</td><td>43.46031547</td></tr>
</table>

您可以在线试用 PHP Fiddle