tags:

views:

168

answers:

2

Hello all. I have an XML document and want to insert a new node at a specific spot using SimpleXML.

The original XML is this:

<epp 
  xmlns="urn:ietf:params:xml:ns:epp-1.0" 
  xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
  xsi:schemaLocation="urn:ietf:params:xml:ns:epp-1.0 epp-1.0.xsd"
>
  <command>
    <create>
      <domain:create 
        xmlns:domain="urn:ietf:params:xml:ns:domain-1.0"
        xsi:schemaLocation="urn:ietf:params:xml:ns:domain-1.0 domain-1.0.xsd"
      >
        <domain:period unit="y"></domain:period>
      </domain:create>
    </create>
  </command>
</epp>

after <domain:create> I need to add the following node:

<domain:ns>
  <domain:hostAttr>
    <domain:hostName></domain:hostName>
    <domain:hostAddr ip="v4"></domain:hostAddr>
  </domain:hostAttr>
</domain:ns>

How can I do that? I have tried this:

$xmlObj = simplexml_load_file('myXMLFile.xml');
$nsNode = $xmlObj->command->create->children(self::OBJ_URI_DOMAIN)->create->addChild('domain:ns');
$hostAttr = $nsNode->addChild('domain:hostAttr');
$hostName = $hostAttr->addChild('domain:hostName');
$hostAddr = $hostAttr->addChild('domain:hostAddr');
$hostAddr->addAtribute('ip', 'v4');

On this first line, I'm getting this warning:

Warning: SimpleXMLElement::addChild() [simplexmlelement.addchild]: Cannot add child. Parent is not a permanent member of the XML tree

On the second line, and because of this, I'm getting:

Fatal error: Call to a member function addChild() on a non-object

Thanks in advance.

Additional notes: - The php version is higher then 5.1; - I have successfully added child nodes later on this same XML.

A: 

You want the child added to <create>.

$nsNode = $xmlObj->command->create->addChild('domain:ns');

The children() method returns a filtered list of child nodes. This list is - just as the error message indicates - not a permanent member of the document tree, it cannot be added to.

Adding a child works on the respective parent element only, or the operation would not be called "addChild", but "addSibling" - and this is not how the concept of the DOM works.

PS: Your second error message ("Call to a member function on a non-object") is the result of regular sloppiness. You can't just use an object without checking that it is actually there, your code lacks this check:

if ($nsNode !== null) {
  $hostAttr = $nsNode->addChild('domain:hostAttr');
  $hostName = $hostAttr->addChild('domain:hostName');
  $hostAddr = $hostAttr->addChild('domain:hostAddr');
  $hostAddr->addAttribute('ip', 'v4');
} else {
  echo "Oops, addChild() failed!";
}
Tomalak
I see. So the error here is due to the fact that I was assuming '<domain:create'> as a child of '<create>' but it isn't ?The nodes to be added need to be siblings of '<domain:period>' and '<domain:period>' is inside '<domain:create>' and '<domain:create>' is inside '<create>' but I'm reading it badly am I? I now better understand the why for this error, and that's a great help, but I still miss why addChild('domain:ns') will do it.later on this same XML I have $xmlObj->command->extension->children(self::EXT_URI_DOMAIN)->create->addChild('ptdomain:autoRenew'); and it works :s
MEM
You cannot add to the return value of `children()`, period. If you need to add to one of the nodes that this method returns, save the return value of that method, pick a particular node from it, and call `addChild()` on that.
Tomalak
sorry, my bad. I've changed the post, $nsNode = $xmlObj->command->create->children(self::OBJ_URI_DOMAIN)->create->addChild('domain:ns'); This is what I intended. So here, we are not accessing the list directly, but a node of that list. And that's the reason why my other commands work.If your last reply still applies after this comment, please let me know. :)
MEM
And it's on that line with this new configuration that the error occours, but again, it doesn't on other lines with the same form, that's the reason for this puzzlement of me. I will forget that the other instructions work, and I will try as suggested. Pass the child list to a variable, access the child list child, and only there, use the addChild() method. :s
MEM
Tried:$listChildren = $xmlObj->command->create->children(self::OBJ_URI_DOMAIN);$nodeCreate = $listChildren->create;$nodeCreate->addChild('domains:ns');no luck.99% it's my fault... I'm just wondering what I'm not getting. :(
MEM
Tomalak thanks for explaining me what the error really means. I will be more carefull next time because of that. :)
MEM
A: 

I cannot reproduce the first error

<?php
echo phpversion(), "\n";
// $xmlObj = simplexml_load_file('myXMLFile.xml');
$xmlObj = getDoc();

$nsNode = $xmlObj->command->create->children('urn:ietf:params:xml:ns:domain-1.0')->create->addChild('domain:ns');
$nsNode->addChild('foo', 'Mary had a little lamb...');
echo $xmlObj->asxml();

function getDoc() {
  return new SimpleXMLElement('<epp 
    xmlns="urn:ietf:params:xml:ns:epp-1.0" 
    xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
    xsi:schemaLocation="urn:ietf:params:xml:ns:epp-1.0 epp-1.0.xsd"
  >
    <command>
      <create>
        <domain:create 
          xmlns:domain="urn:ietf:params:xml:ns:domain-1.0"
          xsi:schemaLocation="urn:ietf:params:xml:ns:domain-1.0 domain-1.0.xsd"
        >
          <domain:period unit="y"></domain:period>
        </domain:create>
      </create>
    </command>
  </epp>');
}

prints

5.3.2
<?xml version="1.0"?>
<epp xmlns="urn:ietf:params:xml:ns:epp-1.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="urn:ietf:params:xml:ns:epp-1.0 epp-1.0.xsd">
    <command>
      <create>
        <domain:create xmlns:domain="urn:ietf:params:xml:ns:domain-1.0" xsi:schemaLocation="urn:ietf:params:xml:ns:domain-1.0 domain-1.0.xsd">
          <domain:period unit="y"/>
        <domain:ns><domain:foo>Mary had a little lamb...</domain:foo></domain:ns></domain:create>
      </create>
    </command>
  </epp>
VolkerK
Thanks a lot for your time VolkerK. Ok... The only difference is that I'm grabbing a XML file instead. I need to keep that in order the maintaining the overall structure. I will remake all step by step and provide some feedback later today - I wish no one to pass what I'm passing now - . :s
MEM
Not sure if you are still with me, I have found that:Ok... I have found the switch, but I haven't seen anything else... still:This works:$nsNode = $xmlObj->command->create->children('urn:ietf:params:xml:ns:domain-1.0')->create->addChild('domain:ns');This doesn't, and throws me the warning:$nsNode = $xmlObj->command->create->children(self::OBJ_URI_DOMAIN)->create->addChild('domain:ns');I have this up on my class:const OBJ_URI_DOMAIN = 'urn:ietf:params:xml:ns:epp:domain-1.0'What could lead to such a behaviour?
MEM
the URIs are different. :s Done. :)Thanks a lot.
MEM