Ссылка. Как обрабатывать пространства имен (теги и атрибуты с двоеточием в) в SimpleXML?

Этот вопрос предназначен как ссылка на ответ на особенно распространенный вопрос, который может иметь разные формы:

  • У меня есть документ XML, который содержит несколько пространств имен; как его разобрать с помощью SimpleXML?
  • Мой XML имеет двоеточие (":") в имени тега, как мне получить доступ к нему с помощью SimpleXML?
  • Как получить доступ к атрибутам в моем XML-файле, когда у них есть двоеточие в имени?

Если ваш вопрос был закрыт как дубликат этого, он может не совпадать с этими примерами, но эта страница должна рассказать вам, что вам нужно знать.

Вот пример:

$xml = ' <?xml version="1.0" encoding="utf-8"?> <document xmlns="http://example.com" xmlns:ns2="https://namespaces.example.org/two" xmlns:seq="urn:example:sequences"> <list type="short"> <ns2:item seq:position="1">A thing</ns2:item> <ns2:item seq:position="2">Another thing</ns2:item> </list> </document> '; $sx = simplexml_load_string($xml); 

Этот код не будет работать ; почему нет?

 foreach ( $sx->list->ns2:item as $item ) { echo 'Position: ' . $item['seq:position'] . "\n"; echo 'Item: ' . (string)$item . "\n"; } 

Первая проблема заключается в том, что ->ns2:item является недопустимым синтаксисом; но изменение его на это тоже не работает :

 foreach ( $sx->list->{'ns2:item'} as $item ) { ... } 

Почему нет, и что вы должны использовать вместо этого?

Что такое пространства имен XML?

Двоеточие (:) в имени тега или атрибута означает, что элемент или атрибут находится в пространстве имен XML . Пространства имен – это способ комбинирования разных форматов / стандартов XML в одном документе и отслеживание имен имен из какого формата. Двоеточие и часть, находящаяся перед ним, на самом деле не являются частью имени тега / атрибута, они просто указывают, в каком пространстве имён оно находится.

Пространство имен XML имеет идентификатор пространства имен , который идентифицируется URI (URL или URN). URI не указывает ни на что, это просто способ, чтобы кто-то «владел» пространством имен. Например, стандарт SOAP использует пространство имен http://www.w3.org/2003/05/soap-envelope а файл OpenDocument использует (среди прочих) urn:oasis:names:tc:opendocument:xmlns:meta:1.0 , В примере в вопросе используются пространства имен http://example.com и https://namespaces.example.org/two .

В документе или разделе документа пространству имен присваивается локальный префикс , который является частью, которую вы видите перед двоеточием. Например, в разных документах пространству имен SOAP может быть предоставлено локальное префиксное soap: SOAP: SOAP-ENV: env: или просто ns1: Эти имена связаны с идентификатором пространства имен с помощью специального атрибута xmlns , например xmlns:soap="http://www.w3.org/2003/05/soap-envelope" . Выбор префикса в конкретном документе полностью произволен и может меняться каждый раз, когда он был сгенерирован без изменения значения.

Наконец, в каждом документе или разделе документа есть пространство имен по умолчанию , которое является пространством имен, используемым для элементов без префикса. Он определяется атрибутом xmlns без : например xmlns="http://www.w3.org/2003/05/soap-envelope" . В приведенном выше примере <list> находится в пространстве имен по умолчанию, которое определяется как http://example.com .

В некоторой степени уникальные атрибуты без префикса никогда не входят в пространство имен по умолчанию, а в виде «пространства имен void», которое стандарт четко не определяет. См.: Пространства имен XML и атрибуты Unprefixed

Как вы получаете доступ к пространствам имен в SimpleXML?

SimpleXML предоставляет два основных метода использования пространств имен:

  • Метод ->children() позволяет вам обращаться к дочерним элементам в определенном пространстве имен. Он эффективно переключает ваш объект на это пространство имен, пока вы не вызовете его снова, чтобы переключиться обратно или в другое пространство имен.
  • Метод ->attributes() работает аналогичным образом, но позволяет вам обращаться к атрибутам в определенном пространстве имен.

Оба этих метода принимают идентификатор пространства имен в качестве первого аргумента. Поскольку эти идентификаторы довольно длинные, может быть полезно определить константу или переменную для представления пространств имен, с которыми вы работаете, поэтому вам не нужно копировать и вставлять полный URI всюду.

Например, приведенный выше пример может стать:

 define('XMLNS_EG2', 'https://namespaces.example.org/two'); define('XMLNS_SEQ', 'urn:example:sequences'); foreach ( $sx->list->children(XMLNS_EG2)->item as $item ) { echo 'Position: ' . $item->attributes(XMLNS_SEQ)->position . "\n"; echo 'Item: ' . (string)$item . "\n"; } 

В качестве короткой руки вы также можете передать методам локальный псевдоним пространства имен, указав второй параметр как true . Помните, что этот префикс может измениться в любое время, например, генератор может назначать префиксы ns1 , ns2 и т. Д. И назначать их в другом порядке, если код немного меняется. Используя эту короткую руку, код будет выглядеть следующим образом:

 foreach ( $sx->list->children('ns2', true)->item as $item ) { echo 'Position: ' . $item->attributes('seq', true)->position . "\n"; echo 'Item: ' . (string)$item . "\n"; } 

(Эта короткая ссылка была добавлена ​​в PHP 5.2, и вы можете увидеть действительно старые примеры, используя более длинную версию с использованием $sx->getNamespaces чтобы получить список пар префикс-идентификатор.)