У меня есть XML, который имеет t:subscriptions
элемент, который содержит несколько t:subscription
дочерние элементы.
Моя главная цель — заменить текущий t:subsciptions
в целом или все t:subsciption
элементы с новыми. На данный момент я создал новый t:subscription
элементы в виде строк (не разбирались в классах dom / simplexml, поэтому мне пришлось использовать метод «отступления»).
Теперь я пытаюсь преобразовать строку в XML с помощью simplexml_load_string, а затем dom_import_simplexml, чтобы добавить / заменить текущие подписки в XML. Я пробовал следующий пример, найденный с этого сайта:
$newsubs = ''; //new XML as string
$sdom = new DOMDocument();
$sdom->loadXML($xml->asXML()); // current XML
//dpm($sdom->saveXML());
$xpath = new DOMXPath($sdom);
// ... x functions generate $newsubs string ...
$remove = $sdom->getElementsByTagName('subscriptions')->item(0); // get t:subscriptions for removal
$remove->parentNode->removeChild($remove); // remove t:subscriptions
$fragment = $sdom->createDocumentFragment();
$fragment->appendXml($newsubs);
$xpaths
->evaluate('//t:member') // this node holds t:subscriptions among others
->item(0) // there's always only one member node
->appendChild($fragment);
debug($sdom->saveXML());
Я зашел так далеко, что только ошибка получена Namespace prefix X on Y is not defined
и это для всех элементов. Скрипт удаляет префиксы пространства имен, хотя они определены в строке XML, например <t:myelement>asdasd</t:myelement>
,
Документ XML, к которому будет добавлен этот XML, уже имеет префикс. Я не понимаю, почему он не может принять префиксный XML и удаляет префикс, а новый документ добавляется в документ? Не имеет смысла
Сообщение об ошибке может означать, что атрибут «xmlns: *» для пространства имен отсутствует в XML или что префикс пространства имен не был зарегистрирован в объекте XPath.
Пространства имен должны быть определены с обеих сторон. Первый — это сам XML.
<foo xmlns="urn:foo"/>
или же
<f:foo xmlns:f="urn:foo"/>
Обе команды разрешаются парсером в одно и то же пространство имен и локальное имя. Вы можете прочитать имя элемента как {urn:foo}:foo
,
Вот несколько * NS-методов в DOM, которые позволяют вам работать с пространством имен. Пространство имен всегда URN. Префикс не подходит для сопоставления.
$node->getElementsByTagNameNS('urn:foo', 'foo')
Префикс предоставляется только в том случае, если он необходим в качестве значения. Например, чтобы создать узел элемента, который его использует.
$document->createElementNS('urn:foo', 'foo'); // no prefix
$document->createElementNS('urn:foo', 'f:foo'); // with prefix "f"
XPath также использует префиксы в выражениях. Но это не должно читать их из документа. использование DOMXpath::registerNamespace()
зарегистрировать собственные префиксы для определенного пространства имен.
В вашем вопросе отсутствует полный XML, поэтому я добавлю небольшой пример Atom. Вы можете видеть, что пространство имен одинаково в XML и в PHP, но префикс отличается:
$xml = <<<'XML'
<?xml version="1.0" encoding="UTF-8"?>
<atom:feed xmlns:atom="http://www.w3.org/2005/Atom">
<atom:title>Example Feed</atom:title>
<atom:entry>
<atom:title>Atom-Powered Robots Run Amok</atom:title>
<atom:id>urn:uuid:1225c695-cfb8-4ebb-aaaa-80da344efa6a</atom:id>
</atom:entry>
</atom:feed>
XML;
$dom = new DOMDocument();
$dom->loadXml($xml);
$xpath = new DOMXPath($dom);
$xpath->registerNamespace('a', 'http://www.w3.org/2005/Atom');
var_dump($xpath->evaluate('string(//a:entry/a:title)'));
Выход:
string(28) "Atom-Powered Robots Run Amok"
Других решений пока нет …