xPath не находит ничего, кроме * - PullRequest
3 голосов
/ 15 сентября 2010

Это начинает меня очень злить.У меня есть этот XML-код:

Обновлен с правильными пространствами имен

<?xml version="1.0" encoding="utf-8"?>

<Infringement xsi:schemaLocation="http://www.movielabs.com/ACNS http://www.movielabs.com/ACNS/ACNS2v1.xsd" xmlns="http://www.movielabs.com/ACNS" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance">
  <Case>
    <ID>...</ID>
    <Status>Open</Status>
  </Case>
  <Complainant>
    <Entity>...</Entity>
    <Contact>...</Contact>
    <Address>...</Address>
    <Phone>...</Phone>
    <Email>...</Email>
  </Complainant>
  <Service_Provider>
    <Entity>...</Entity>
    <Address></Address>
    <Email>...</Email>
  </Service_Provider>
  <Source>
    <TimeStamp>...</TimeStamp>
    <IP_Address>...</IP_Address>
    <Port>...</Port>
    <DNS_Name></DNS_Name>
    <Type>...</Type>
    <UserName></UserName>
    <Number_Files>1</Number_Files>
    <Deja_Vu>No</Deja_Vu>
  </Source>
  <Content>
    <Item>
      <TimeStamp>...</TimeStamp>
      <Title>...</Title>
      <FileName>...</FileName>
      <FileSize>...</FileSize>
      <URL></URL>
    </Item>
  </Content>
</Infringement>

И этот код PHP:

<?php 
    $data = urldecode($_POST["xml"]);
    $newXML = simplexml_load_string($data);

    var_dump($newXML->xpath("//ID"));
?>

Я сбросил только$ newXML и получил тонны данных, но единственный запущенный мною xPath, который возвратил что-либо, кроме пустого массива, был "*"

Не "// ID", должен найти все узлы идентификатора в документе?Почему не работает?

Спасибо

Ответы [ 5 ]

8 голосов
/ 15 сентября 2010

Кажется, что корневой элемент вашего XML-документа имеет пространство имен по умолчанию с URI "http://www.movielabs.com/ACNS". Это означает, что все элементы в вашем документе принадлежат этому пространству имен. Проблема в том, что все выражения XPath, не имеющие префикса пространства имен,поиск элементов, которые не принадлежат ни к какому пространству имен. Для поиска элементов (или атрибутов ...) из определенного пространства имен необходимо зарегистрировать URI пространства имен для какого-либо префикса, а затем использовать этот префикс в выражении XPath.

В случае PHP SimpleXML это делается примерно так:

$newXML = simplexml_load_string($data);
$newXML->registerXPathNamespace('prefix', 'http://www.movielabs.com/ACNS');
var_dump($newXML->xpath("//prefix:ID"));

prefix может быть практически любым текстом, но URI пространства имен должен точно соответствовать тому, который используется в вашем документе XML.

7 голосов
/ 15 сентября 2010

Я сбросил только $ newXML и получил тонны данных, но единственный запущенный мной xPath, который возвратил что-либо, кроме пустого массива, был "*"

Так что жевернулся с var_dump($newXML->xpath("*"));?<Infringement>?

Если проблема заключается в пространствах имен, попробуйте следующее:

var_dump($newXML->xpath("//*[local-name() = 'ID']"));

Это будет соответствовать любому элементу документа, имя которого равно 'ID', независимо от того,пространства имен.

Мой материал сработает, если я заменю все "xmlns" на "ns"

Подождите, что?Вы уверены, что показали нам все атрибуты, связанные с xmlns, в документе?

Обновление: Вопрос был отредактирован, чтобы показать, что XML действительно имеет объявление пространства имен по умолчанию.Это объясняет исходную проблему: ваше выражение XPath выбирает элементы ID, которые не находятся в пространстве имен, но элементы в вашем документе находятся в пространстве имен ACNS movielabs, благодаря объявлению пространства имен по умолчанию.

Объявление xmlns="http://www.movielabs.com/ACNS" onэлемент означает «этот элемент, и все потомки, которые не имеют префикса пространства имен (например, ID), находятся в пространстве имен, представленном URI пространства имен» http://www.movielabs.com/ACNS'." (если только у промежуточного потомка нет другого объявления пространства имен по умолчанию, котороезамаскировал бы этот.)

Поэтому используйте мой local-name() ответ выше, чтобы игнорировать пространства имен, или используйте технику Джассо, чтобы указать ACNS для видеоряда и использовать его по назначению.

1 голос
/ 15 сентября 2010

используйте это для любого пространства имен:

var_dump($newXML->xpath("//*:ID"));
0 голосов
/ 25 августа 2014

В элементе документа определено пространство имен xml (атрибут xmlns="http://www.movielabs.com/ACNS").Пространство имен - это URL http://www.movielabs.com/ACNS.Это должно иметь глобально уникальную строку (URN).Из-за этого URL-адреса используются часто.Вероятность того, что кто-то использует ваш домен для пространства имен, очень мала, и вы можете разместить некоторую документацию по URL.

Анализатор XML разрешает пространства имен.Узел получает 4 свойства.

Для <Infringement xmlns="http://www.movielabs.com/ACNS"/>:

$namespaceURI => http://www.movielabs.com/ACNS
$localName => Infringement
$prefix => 
$nodeName => Infringement

Для <movie:Infringement xmlns:movie="http://www.movielabs.com/ACNS"/>:

$namespaceURI => http://www.movielabs.com/ACNS
$localName => Infringement
$prefix => movie
$nodeName => movie:Infringement

$namespaceURI и $localName стабильны.Два других зависят от префикса.Префикс является псевдонимом для пространства имен.Пространство имен uri длинное и сложное, что делает XML более трудным для чтения и записи при использовании для каждого элемента / атрибута.Но вы можете интерпретировать узлы элемента следующим образом:

{http://www.movielabs.com/ACNS}:Infringement

Таким образом, пространство имен - это единственное, что определяет, что означают узлы, а не префикс / псевдоним.Префиксы могут быть переопределены для подэлемента.

<foo xmlns="urn:foo"><bar xmlns="urn:bar"/></foo>

Xpath использует ту же концепцию с собственным распознавателем.Вы регистрируете свои собственные префиксы для пространства имен.Таким образом, не имеет значения, как префиксы используются в XML, должно совпадать только пространство имен URI.

В DOM вы делаете это на экземпляре DOMXPath:

$dom = new DOMDocument();
$dom->loadXml($xml);
$xpath = new DOMXpath($dom);
$xpath->registerNamespace('movie', 'http://www.movielabs.com/ACNS');

var_dump(
  $xpath->evaluate('string(/movie:Infringement/movie:Case/movie:ID)')
);

В SimpleXML, вы можете зарегистрировать пространство имен в SimpleXMLElement.

$element = simplexml_load_string($xml);
$element->registerXpathNamespace('movie', 'http://www.movielabs.com/ACNS');
var_dump(
  (string)$element->xpath('/movie:Infringement/movie:Case/movie:ID')[0]
);

СОВЕТ: Пространство имен по умолчанию используется только для элементов, атрибуты находятся в «пространстве имен no / empty», если у них нет префикса.

0 голосов
/ 15 сентября 2010

Я не очень разбираюсь в PHP API XML, но я подозреваю, что проблема заключается в пространствах имен.В зависимости от того, как работает этот метод xpath, он может искать элементы ID с пустым пространством имен.Ваши элементы ID наследуют свое пространство имен от корневого элемента.

...