2014-06-07 3 views
2

Я пытаюсь разобрать XML, как это:Анализировать XML с пространствами имен с SimpleXMLparser PHP

<?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; 
} 

в $ выходе у меня есть полный XML, тонн координат в gml:point

Но я пытаюсь добраться до точек с помощью пространств имен, но я должен делать что-то неправильно, потому что я не могу ничего, кроме массива слова печати (даже с помощью print_r ...)

+0

Это ваш atual источник XML? Похоже, что он не был хорошо сформирован. Он не будет разбираться. – helderdarocha

+0

Я изменил xml. Теперь я установил полный. Предыдущий был изменен только для того, чтобы включить пару пунктов. Этот xml - это то, что я получил от webservice – user1298272

+1

Как и в случае сбоя, если вы все равно полагаетесь на префиксы в документе (заданные 'getNamespaces (true)'), вы можете просто использовать их непосредственно с '-> детьми ("p", true) '. Лучше хотя бы определить свой собственный массив или набор констант с фактическими URI пространства имен, если код, генерирующий XML, изменится в будущем и отобразит разные префиксы с тем же значением. – IMSoP

ответ

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

Это было бы проще с помощью XPath, поскольку у вас есть узлы, вложенные глубоко в переменные пространства имен, но так как вы используете SimpleXML Я покажу вам решение с использованием этой структуры.

Это

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

не будет работать, потому что корневой узел не имеет детей в p пространстве имен. Вы должны перемещаться по дереву, пока не находитесь в правильном контексте. С 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); 

С этого момента, пространство имен Безразлично» t, поэтому вы можете нормально перемещаться и получать данные в элементах 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 вы можете попробовать в Интернете.

Смежные вопросы