I have a XML that has a t:subscriptions
element that holds multiple t:subscription
child elements.
My main goal is to replace current t:subsciptions
as a whole or all t:subsciption
elements with new ones. At the moment I have created new t:subscription
elements as strings (didn't get a grasp of dom/simplexml classes so I had to use "fallback" method).
Now I'm trying to convert string to XML by simplexml_load_string and then dom_import_simplexml in order to append/replace current subscriptions in XML. I've tried following example found from this site:
$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());
I've come so far that only error received is Namespace prefix X on Y is not defined
and this is for all elements. Script removes namespace prefixes although they are defined in xml string eg <t:myelement>asdasd</t:myelement>
.
The XML document that this XML is going to be added is already prefixed. I don't get it why it can't accept prefixed XML and strips prefix away and yet new XML get appended to the document? Doesn't make sense.
The error message can mean that the "xmlns:*" attribute for the namespace is missing in the XML or that the namespace prefix was not registered on the XPath object.
Namespaces need to be defined on both sides. The first is the XML itself.
<foo xmlns="urn:foo"/>
or
<f:foo xmlns:f="urn:foo"/>
Are both resolved by the parser to the same namespace and local name. You can read the element name as {urn:foo}:foo
.
Here are several *NS methods on the DOM that allow you to work with a namespace. The namespace is always the URN. The prefix is not relevant for matching.
$node->getElementsByTagNameNS('urn:foo', 'foo')
The prefix is only provided if it is needed as a value. For example to create an element node that uses it.
$document->createElementNS('urn:foo', 'foo'); // no prefix
$document->createElementNS('urn:foo', 'f:foo'); // with prefix "f"
XPath uses the prefixes in the expressions, too. But it should not read them from the document. Use DOMXpath::registerNamespace()
to register an own prefixes for a specific namespace.
Your question is missing the full XML so I will add a small Atom example. You can see that the namespace is the same in the XML and in the PHP, but the prefix is different:
$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)'));
Output:
string(28) "Atom-Powered Robots Run Amok"