【问题标题】:Parse xml with namespaces with SimpleXMLparser php使用 SimpleXMLparser php 解析带有命名空间的 xml
【发布时间】:2014-07-28 19:20:19
【问题描述】:

我正在尝试解析这样的 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 的每一行保存到数据库,但目前我很高兴在 webpace 中打印它们 (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 我有完整的 xml,gml:point 中的大量坐标

但我试图使用命名空间来达到目的,但我必须做错事,因为除了 Array word 之外我无法打印任何内容(即使使用 print_r...)

【问题讨论】:

  • 那是你的 XML 源吗?它似乎没有很好地形成。它不会解析。
  • 我更改了 xml。现在我设置了一个完整的。前一个被修改只是为了包括几点。这个 xml 是我从网络服务收到的
  • 顺便说一句,如果您仍然依赖文档中的前缀(由getNamespaces(true) 提供),您可以直接将它们与-&gt;children("p", true) 一起使用。最好用实际的命名空间 URI 定义自己的数组或常量集,以防生成 XML 的代码在将来发生变化并选择具有相同含义的不同前缀。

标签: php xml simplexml


【解决方案1】:

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

这个

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

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

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

现在你可以循环 pointPropertychildren 并且你将拥有你的 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,您可以在线试用。

【讨论】:

    【解决方案2】:

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

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

    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"
    }
    

    【讨论】:

      猜你喜欢
      • 2012-12-05
      • 1970-01-01
      • 2012-06-11
      • 1970-01-01
      • 1970-01-01
      • 2013-02-01
      • 2013-04-30
      • 1970-01-01
      相关资源
      最近更新 更多