Wahid Masud
Wahid Masud

Reputation: 1093

SimpleXMLElement::addChild() is not working

In my php code I have two variables $parent and $child. Both of them have some xml data. in $parent variable there is a tag called <payheads> which may contain several <payhead> tags. In $child variable there is only one <payhead> tag. What I want is, I want to add that child in the end of the <payheads> tag of $parent variable. My Code is given below:

<?php

$parent = new SimpleXMLElement('<review_sr><status>Review Complete</status><payheads><payhead><code>ABAS</code><old_value>0.00</old_value><new_value>63570.00</new_value><review_id>1234567890</review_id><review_time>20160614:11:00:47</review_time><status>Accepted</status></payhead></payheads><current_gross_allowance>50481.00</current_gross_allowance><review_gross_allowance>114051.00</review_gross_allowance></review_sr>');

$child = new SimpleXMLElement('<source><payhead><code>DMG</code><old_value>500.00</old_value><new_value>0.00</new_value><review_id>1234567890</review_id><review_time>20160620:12:41:17</review_time><status>Accepted</status></payhead></source>');
$child = $child->xpath('//payhead'); //This is to ignore the xml declaration that is automatically produced by the SimpleXMLElement constructor
$child = $child[0];                 //I've tried LIBXML_NOXMLDECL  but its not working, that's why these two lines.

//var_dump($parent);
//var_dump($child->asXML());

$parentNode = $parent->xpath('//payheads');
$parentNode[0]->addChild('payhead', $child);
//var_dump($parentNode[0]);
foreach($parent as $key=>$value)
    foreach($value as $key=>$value)
        var_dump($value); //only 1 payhead is shown. but there should be 2 of them.

?>  

Actual Output:

object(SimpleXMLElement)[5]
  public 'code' => string 'ABAS' (length=4)
  public 'old_value' => string '0.00' (length=4)
  public 'new_value' => string '63570.00' (length=8)
  public 'review_id' => string '1234567890' (length=10)
  public 'review_time' => string '20160614:11:00:47' (length=17)
  public 'status' => string 'Accepted' (length=8)

object(SimpleXMLElement)[6]

Expected Output:

object(SimpleXMLElement)[5]
  public 'code' => string 'ABAS' (length=4)
  public 'old_value' => string '0.00' (length=4)
  public 'new_value' => string '63570.00' (length=8)
  public 'review_id' => string '1234567890' (length=10)
  public 'review_time' => string '20160614:11:00:47' (length=17)
  public 'status' => string 'Accepted' (length=8)

object(SimpleXMLElement)[6]  
  public 'code' => string 'DMG' (length=4)
  public 'old_value' => string '500.00' (length=4)
  public 'new_value' => string '0.00' (length=8)
  public 'review_id' => string '1234567890' (length=10)
  public 'review_time' => string '20160620:12:41:17' (length=17)
  public 'status' => string 'Accepted' (length=8)

What did I do wrong?

Upvotes: 3

Views: 1815

Answers (2)

phreakv6
phreakv6

Reputation: 2165

Please try this. The problem is that addChild() of simplexmlelement expects a string and you are trying to append an object which it typecasts to null.

public SimpleXMLElement SimpleXMLElement::addChild ( string $name [, string $value [, string $namespace ]] )

You need to use DOM and appendChild to DOM instead.

function sxml_append(SimpleXMLElement $to, SimpleXMLElement $from) {
    $toDom = dom_import_simplexml($to);
    $fromDom = dom_import_simplexml($from);
    $toDom->appendChild($toDom->ownerDocument->importNode($fromDom, true));
}

$parent = new SimpleXMLElement('<review_sr><status>Review Complete</status><payheads><payhead><code>ABAS</code><old_value>0.00</old_value><new_value>63570.00</new_value><review_id>1234567890</review_id><review_time>20160614:11:00:47</review_time><status>Accepted</status></payhead></payheads><current_gross_allowance>50481.00</current_gross_allowance><review_gross_allowance>114051.00</review_gross_allowance></review_sr>');

$child = new SimpleXMLElement('<source><payhead><code>DMG</code><old_value>500.00</old_value><new_value>0.00</new_value><review_id>1234567890</review_id><review_time>20160620:12:41:17</review_time><status>Accepted</status></payhead></source>');
$child = $child->xpath('//payhead'); //This is to ignore the xml declaration that is automatically produced by the SimpleXMLElement constructor
$child = $child[0];                 //I've tried LIBXML_NOXMLDECL  but its not working, that's why these two lines.

$parentNode = $parent->xpath('//payheads');
sxml_append($parentNode[0],$child[0]);

var_dump($parent);

Upvotes: 1

Niet the Dark Absol
Niet the Dark Absol

Reputation: 324620

addChild takes string arguments - the first being the tag name to create, the (optional) second being its text content, and the (optional) third being the namespace of the element.

You can't just pass it another element to use instead. It seems that SimpleXMLElement is in fact too simple for this kind of operation.

Instead, consider using DOMDocument, like so:

<?php
$parent = new DOMDocument();
$parent->loadXML('<review_sr><status>Review Complete</status><payheads><payhead><code>ABAS</code><old_value>0.00</old_value><new_value>63570.00</new_value><review_id>1234567890</review_id><review_time>20160614:11:00:47</review_time><status>Accepted</status></payhead></payheads><current_gross_allowance>50481.00</current_gross_allowance><review_gross_allowance>114051.00</review_gross_allowance></review_sr>');

$child = new DOMDocument();
$child->loadXML('<source><payhead><code>DMG</code><old_value>500.00</old_value><new_value>0.00</new_value><review_id>1234567890</review_id><review_time>20160620:12:41:17</review_time><status>Accepted</status></payhead></source>');
$childNode = $child->getElementsByTagName('payhead')->item(0);

$parentNode = $parent->getElementsByTagName('payheads')->item(0);
$parentNode->appendChild($child);
foreach($parent->getElementsByTagName('payhead') as $payhead) {
    var_dump($payhead);
}

If need be, you can then take these payheads and pass them to SimpleXMLElement to get their properties in a very simple way:

$simplePayhead = simplexml_import_dom($payhead);
var_dump($simplePayhead);

Upvotes: 2

Related Questions