Don't crosspost to two irrelevant lists, please Derick
On Sun, 14 Mar 2004, Vivian Steller wrote: > hello, > > once again a post about the tricky namespaces. I played with the following > functions concerning namespaces: > > domdocument->createElementNS > domdocument->createAttributeNS > domelement->setAttributeNS > domelement->getAttributeNS > (domelement->hasAttributeNS) > > as i found out the behavior of some functions differs when handling > namespaces. maybe we can start a thread thinking about this behavior - at > the moment i don't have the "enlightened" view into this very complex > theme. would be nice if you could help me/us understanding namespaces a bit > more... > > ok here are the things i found out. copy the code to your editor and step > through the examples - the important output is given in the comments. > Thanks for taking time to that :) > > /*############################ START ############################*/ > <pre> > > /* SIMPLE NAMESPACE EXAMPLE */ > <?php > $doc = new DomDocument(); > $xpath = new DomXPath($doc); > > /* SIMPLE NAMESPACE EXAMPLE */ > $node1 = $doc->createElementNS("namespaceURI", "nodeName"); > $node1 = $doc->appendChild($node1); > > print(htmlspecialchars("\n" . $doc->saveXML() . "\n")); > // Output > // > <nodeName xmlns="namespaceURI"/> > > $namespaces = $xpath->query("//namespace::*"); > foreach($namespaces as $item) { > print($item->nodeName . " = " . $item->nodeValue . "\n"); > } > // Output > // > xmlns:xml = http://www.w3.org/XML/1998/namespace > // > xmlns = namespaceURI > $doc->removeChild($node1); > ?> > > Right behavior so far! > > > > /* NAMESPACE WITH PREFIX EXAMPLE */ > <?php > /* NAMESPACE WITH PREFIX EXAMPLE */ > $node2 = $doc->createElementNS("namespaceURI", "prefix:localName"); > $node2 = $doc->appendChild($node2); > > print(htmlspecialchars("\n" . $doc->saveXML() . "\n")); > // Output > // > <prefix:localName xmlns:prefix="namespaceURI"/> > > $namespaces = $xpath->query("//namespace::*"); > foreach($namespaces as $item) { > print($item->nodeName . " = " . $item->nodeValue . "\n"); > } > // Output > // > xmlns:xml = http://www.w3.org/XML/1998/namespace > // > xmlns:prefix = namespaceURI > > // $doc->removeChild($node2); > ?> > > Still right behavior! > > > > /* NAMESPACE WITH EXISTING PREFIX EXAMPLE */ > <?php > /* NAMESPACE WITH EXISTING PREFIX EXAMPLE */ > $node3 = $doc->createElementNS("namespaceURI", "localName"); > $node3 = $node2->appendChild($node3); > > print(htmlspecialchars("\n" . $doc->saveXML() . "\n")); > // Output > // > <prefix:localName xmlns:prefix="namespaceURI"> ¬ > // <prefix:localName/> ¬ > // </prefix:localName> > > $namespaces = $xpath->query("//namespace::*"); > foreach($namespaces as $item) { > print($item->nodeName . " = " . $item->nodeValue . "\n"); > } > // Output > // > xmlns:xml = http://www.w3.org/XML/1998/namespace (node2) > // > xmlns:prefix = namespaceURI > (node2) > // > xmlns:xml = http://www.w3.org/XML/1998/namespace (node3) > // > xmlns:prefix = namespaceURI > (node3) > > // $doc->removeChild($node3); > ?> > > Right behavior, but namespace node will be removed, xpath-expression shows > prefix - thats still right. > > > > /* IMPORT NAMESPACE NODE WITHOUT CHILDREN EXAMPLE */ > <?php > /* IMPORT NAMESPACE NODE WITHOUT CHILDREN EXAMPLE */ > $newDoc = new DomDocument(); > $newXpath = new DomXPath($newDoc); > > $newNode3 = $newDoc->importNode($node3); // second argument $deep = > FALSE!! > $newNode3 = $newDoc->appendChild($newNode3); > > print(htmlspecialchars("\n" . $newDoc->saveXML() . "\n")); > // Output > // > <localName/> > > $newNamespaces = $newXpath->query("//namespace::*"); > foreach($newNamespaces as $item) { > print($item->nodeName . " = " . $item->nodeValue . "\n"); > } > // Output > // > xmlns:xml = http://www.w3.org/XML/1998/namespace (newNode3) > > $newDoc->removeChild($newNode3); > ?> > > Maybe right behavior, but i think loosing the namespace while importing the > node without its children is a bit dangerous... > > > > /* IMPORT NAMESPACE NODE EXAMPLE */ > <?php > /* IMPORT NAMESPACE NODE EXAMPLE */ > $newNode3 = $newDoc->importNode($node3, TRUE); // second argument $deep = > TRUE now!! > $newNode3 = $newDoc->appendChild($newNode3); > > print(htmlspecialchars("\n" . $newDoc->saveXML() . "\n")); > // Output > // > <prefix:localName xmlns:prefix="namespaceURI"/> > > $newNamespaces = $newXpath->query("//namespace::*"); > foreach($newNamespaces as $item) { > print($item->nodeName . " = " . $item->nodeValue . "\n"); > } > // Output > // > xmlns:xml = http://www.w3.org/XML/1998/namespace (newNode3) > // > xmlns:prefix = namespaceURI > (newNode3) > > $newDoc->removeChild($newNode3); > ?> > > Now the namespace node will be imported as well, but it is not possible > to import the "namespaced" node without its children... > > > > /* SET A NAMESPACE ATTRIBUTE WITHOUT PREFIX AND UNDEFINED NAMESPACE */ > <?php > /* SET A NAMESPACE ATTRIBUTE WITHOUT PREFIX AND UNDEFINED NAMESPACE */ > //$node3->setAttributeNS("attrNamespaceURI", "attrName", "attrValue"); > // Output > // > Fatal error: Uncaught exception 'domexception' with message > 'Namespace Error' > ?> > > Error message is acceptable because attribute nodes could not have their own > "xmlns" attributes! They have to be defined with a prefix (if their is no > prefix defined for this namespace!)... Therefor the folling example should > not occur an error... > > <?php > /* SET A NAMESPACE ATTRIBUTE WITH EXISTING NAMESPACE */ > //$node3->setAttributeNS("namespaceURI", "attrName", "attrValue"); > // Output would be > // > <prefix:localName xmlns:prefix="namespaceURI"> > // <prefix:localName prefix:attrName="attrValue"/> > // </prefix:localName> > ?> > > And it doesn't. Right! The import of this node will be done correctly! > > > > /* SET A NAMESPACE ATTRIBUTE WITH PREFIX AND UNDEFINED NAMESPACE EXAMPLE */ > <?php > $node3->setAttributeNS("attrNamespaceURI", "prefix:attrName", "attrValue"); > > print(htmlspecialchars("\n" . $doc->saveXML() . "\n")); > // Output > // > <prefix:localName xmlns:prefix="namespaceURI"> ¬ > // <prefix:localName xmlns:prefix="attrNamespaceURI" > prefix:attrName="attrValue"/> ¬ > // </prefix:localName> > > $namespaces = $xpath->query("//namespace::*"); > foreach($namespaces as $item) { > print($item->nodeName . " = " . $item->nodeValue . "\n"); > } > // Output > // > xmlns:xml = http://www.w3.org/XML/1998/namespace (node2) > // > xmlns:prefix = namespaceURI > (node2) > // > xmlns:xml = http://www.w3.org/XML/1998/namespace (node3) > // > xmlns:prefix = attrNamespaceURI > (node3) > > // $doc->removeChild($node3); > print("Node3 namespace: " . $node3->namespaceURI . "\n"); > // Output > // > Node3 namespace: namespaceURI > ?> > > Seems confusing but namespace of node is still "namespaceURI" > And it will result in a conflict in the following example... > > > > /* IMPORT NAMESPACE NODE WITH NAMESPACE-PREFIX DEFINITION EXAMPLE */ > <?php > /* IMPORT NAMESPACE NODE EXAMPLE */ > $newNode3 = $newDoc->importNode($node3, TRUE); // second argument $deep = > TRUE now!! > $newNode3 = $newDoc->appendChild($newNode3); > > print(htmlspecialchars("\n" . $newDoc->saveXML() . "\n")); > // Output > // > <prefix:localName xmlns:prefix="attrNamespaceURI" > prefix:attrName="attrValue"/> > > $newNamespaces = $newXpath->query("//namespace::*"); > foreach($newNamespaces as $item) { > print($item->nodeName . " = " . $item->nodeValue . "\n"); > } > // Output > // > xmlns:xml = http://www.w3.org/XML/1998/namespace (newNode3) > // > xmlns:prefix = namespaceURI > (newNode3) > print("NewNode3 namespace: " . $newNode3->namespaceURI . "\n"); > // Output > // > NewNode3 namespace: attrNamespaceURI > > $newDoc->removeChild($newNode3); > $node2->removeChild($node3); > ?> > > WOW!! NamespaceURI has been changed while importing node - i think > that this behavior isn't right yet. NamespaceURI shouldn't depend on > xmlns:prefix attribute - instead it simply should loose its prefix and > set its "xmlns" attribute to its current namespaceURI! > > > > /* SET A NAMESPACE ATTRIBUTE WITH NEW ATTRIBUTE NODE EXAMPLE */ > I'm now changing to node2 - getting to complicated > <?php > //$attr2 = $doc->createAttributeNS("attrNamespaceURI", "prefix:attrName"); > // Output > // > Fatal error: Uncaught exception 'domexception' with message > 'Namespace Error' > ?> > > It seems that the behavior handling namespaces isn't the same in > DomDocument::createAttributeNS() and DomElement::setAttributeNS(), as you > can see in the > SET A NAMESPACE ATTRIBUTE WITH PREFIX AND UNDEFINED NAMESPACE EXAMPLE > > But using a new namespace-prefix it will work correctly. > <?php > $attr2 = $doc->createAttributeNS("attrNamespaceURI", "newPrefix:attrName"); > // Output: > // > <prefix:localName xmlns:prefix="namespaceURI" > xmlns:newPrefix="attrNamespaceURI"/> > ?> > > Note: the "xmlns:newPrefix" declaration will be appended to the root > node of the document on creation of this NS attribute. This could > result in trouble while cloning/importing/deleting a node holding an > "newPrefix"ed attribute!? > > <?php > $node3 = $doc->createElementNS("namespaceURI", "nodeName"); > $node3 = $node2->appendChild($node3); > $node3->appendChild($attr2); > > print(htmlspecialchars("\n" . $doc->saveXML() . "\n")); > // Output > // > <prefix:localName xmlns:prefix="namespaceURI" > xmlns:newPrefix="attrNamespaceURI"> > // <prefix:nodeName newPrefix:attrName=""/> > // </prefix:localName> > > $namespaces = $xpath->query("//namespace::*"); > foreach($namespaces as $item) { > print($item->nodeName . " = " . $item->nodeValue . "\n"); > } > // Output > // > xmlns:xml = http://www.w3.org/XML/1998/namespace (node2) > // > xmlns:newprefix = attrNamespaceURI > (node2) > // > xmlns:prefix = namespaceURI > (node2) > // > xmlns:xml = http://www.w3.org/XML/1998/namespace (node3) > // > xmlns:newprefix = attrNamespaceURI > (node3) > // > xmlns:prefix = namespaceURI > (node3) > $node2->removeChild($node3); > // Output > // > <prefix:localName xmlns:prefix="namespaceURI" > xmlns:newPrefix="attrNamespaceURI"/> > ?> > As you can see the "xmlns:newPrefix" attribute is still appended to the root > node of the document. Because of the lack of a (reasonable) possibility to > remove an "xmlns" declaration the reset of an attribute using this prefix > will result in an error: > > <?php > // $attr2 = $doc->createAttributeNS("newAttrNamespaceURI", > "newPrefix:attrName"); > // Output > // > Fatal error: Uncaught exception 'domexception' with message > 'Namespace Error' > ?> > > I think it would be easier to append the "xmlns" declarations on those nodes > which have an attribute/child of this namespace. > > > > /* SET AN XMLNS NAMESPACE ATTRIBUTE EXAMPLE */ > As I said before there is no (reasonable) possiblity to remove an "xmlns" > declaration (you could do this by cloning nodes in the hope for a bug in the > source leading to the loss of this declaration... very uncomforable:). > > But there is a possibility to check if a xmlns is defined using xpath (I use > this xpath in this document all the time). > > I found out that you also can set an "xmlns" declaration using the right > namespaces (which you can find in the sources of libxml and ext/dom). > Have a look: > > <?php > // xmlns Namespace: "http://www.w3.org/2000/xmlns/" > // xml Namespace: "http://www.w3.org/XML/1998/namespace" > $node2->setAttributeNS("http://www.w3.org/2000/xmlns/", > "xmlns:anotherNewPrefix", "anotherNewNamespace"); > > print(htmlspecialchars("\n" . $doc->saveXML() . "\n")); > // Output > // > <prefix:localName xmlns:prefix="namespaceURI" > xmlns:newPrefix="attrNamespaceURI" > xmlns:anotherNewPrefix="anotherNewNamespace"/> > > $namespaces = $xpath->query("//namespace::*"); > foreach($namespaces as $item) { > print($item->nodeName . " = " . $item->nodeValue . "\n"); > } > // Output > // > xmlns:xml = http://www.w3.org/XML/1998/namespace (node2) > // > xmlns:anotherNewPrefix = anotherNewNamespace (node2) > // > xmlns:newprefix = attrNamespaceURI > (node2) > // > xmlns:prefix = namespaceURI > (node2) > ?> > > This is very fine but the behavior (in this case) isn't very logic: setting > an elements'/attributes' namespace the intepreter checks whether a prefix is > defined for this namespace or not. Though the following expression should > not > result in an error while a prefix for the used namespace is defined already: > > <?php > $node2->setAttributeNS("http://www.w3.org/2000/xmlns/", > "justAnotherNewPrefix", "justAnotherNewNamespace"); > // Output: > // > Fatal error: Uncaught exception 'domexception' with message > 'Namespace Error' > ?> > > But unforunately it does! You could solve this problem by simply setting the > "http://www.w3.org/2000/xmlns/" namespace as a default namespace like > "http://www.w3.org/XML/1998/namespace". Then the behavior would be more > consequent... > > </pre> > > /*############################ END ############################*/ > > Ok I think this is enough about namespaces for today. I hope i could help > someone understanding namespaces and the problems with it. > > Any comments would be appreciated. > > Thanks in advance. > > vivi > > -- PHP General Mailing List (http://www.php.net/) To unsubscribe, visit: http://www.php.net/unsub.php