Синтаксический анализ XML с использованием пространств имен с помощью SimpleXML - PullRequest
2 голосов
/ 25 августа 2011

Я пытаюсь найти наиболее эффективный способ синтаксического анализа довольно сложного XML с помощью SimpleXML, и я застрял, когда в документе есть пространства имен.

Хорошо, мой 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 ]

1 голос
/ 25 августа 2011

Рассматривали ли вы возможность использования SimpleXML 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' );
0 голосов
/ 16 ноября 2013

Вы можете получить доступ к имени события по коду:

$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 с пространством имен, можно найти в моем сообщении Анализ XML с пространством имен с помощью SimpleXML в PHP .XML генерируется из выходного сообщения Salesforce, которое содержит пространство имен XML.Я использую SimpleXML, чтобы разобрать его с помощью children ().

0 голосов
/ 25 августа 2011

В вашем примере, это не должно быть $children->start['year'] не $data->start['year']?

Вот пример того, как это работает:

http://codepad.org/8i0fHYdo

0 голосов
/ 25 августа 2011

Вы можете использовать что-то вроде, прежде чем использовать simplexml_load_string:

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

См. http://php.net/manual/en/function.preg-replace.php для объяснения параметра замены ("$ 1 $ 2 $ 3").

Это изменится <ns:eventinfo> на <nseventinfo>

...