1

Let's say I have the following .xml file:

<?xml version="1.0" encoding="UTF-8"?>
<root>
  <item>
    <name>Foo</name>
  </item>
  <item>
    <name>Bar</name>
  </item>
 </root>

In this sample file, I'm trying to append new nodes <item> to node <root> after the last node <item>.

I'm trying to append newly created <item> nodes after the last <item> node in the <root> node in the .xml file.

<?php
  $file = new DOMDocument;
  $file->load("xml.xml");
  $file->loadXML($file->saveXML());

  $root = $file->getElementsByTagName('root')->item(0);

  foreach (["Foo_1", "Bar_2", "Foo_3", "Bar_4"] as $val) {
    $item = new DOMElement('item');
    $item->appendChild(new DOMElement('name', $val));
    $root->appendChild(item);
  }

?>

But I'm getting an error:

Fatal error: Uncaught Error: Call to a member function appendChild() on null in C:\Users\pfort\Desktop\p.php:12 Stack trace: #0 {main} thrown in C:\Users\user_acer\Desktop\p.php on line 12

What am I doing wrong?

2 Answers 2

1

There's multiple issues with your example code. I will address the error you received first:

There is no element <terminy> in your example XML, so

$root = $file->getElementsByTagName('terminy')->item(0);

will return null. That's why you are receiving the

Call to a member function appendChild() on null

error at

$root->appendChild(item);

Also, item is a typo, because it's not a valid variable name (but a name for a non-existent constant); you meant $item.

I'm assuming "terminy" means something similar to "root" in your native language and that you actually meant to write

$root = $file->getElementsByTagName('root')->item(0);

By the way: if you want a reference to the root node of an XML document, you can also use $file->docomentElement.

However, there are other issues with your example code:

$file->load("xml.xml");
$file->loadXML($file->saveXML()); // why are you reloading it in this way?

The last line is unnecessary. You are reloading the same XML again. Is it for formatting purposes? If so, there's a better option available:

$file->preserveWhiteSpace = false;
$file->formatOutput = true;
$file->load("xml.xml");

Lastly: you cannot append children to a node that has not been associated with a document yet. So, to create a new item and associate it with the document, you either do (recommended):

// automatically associate new nodes with document
$item = $file->createElement('item');
$item->appendChild($file->createElement('name', $val));

or (more cumbersome):

// import nodes to associate them with document
$item = $file->importNode(new DOMElement('item'));
$item->appendChild($file->importNode(new DOMElement('name', $val)));

So, putting it all together it becomes:

<?php

$xml = <<<'XML'
<?xml version="1.0" encoding="UTF-8"?>
<root>
  <item>
    <name>Foo</name>
  </item>
  <item>
    <name>Bar</name>
  </item>
 </root>
XML;

$file = new DOMDocument;
$file->preserveWhiteSpace = false;
$file->formatOutput = true;
$file->loadXML($xml); // (for demo purpose loading above XML) replace this with $file->load("xml.xml"); in your actual code

$root = $file->documentElement;

foreach (["Foo_1", "Bar_2", "Foo_3", "Bar_4"] as $val) {
  $item = $file->createElement('item');
  $item->appendChild($file->createElement('name', $val));
  $root->appendChild($item);
}

echo $file->saveXML();
Sign up to request clarification or add additional context in comments.

1 Comment

Thank you very much for your help and for factual remarks. Last night I was too tired to find a solution. Your solution helped me optimize the existing working php code. @Decent Dabbler
0

**PROBLEM SOLVED**

I lost too much time on this problem. The good news is, I already know how to get what I need. Here I offer a solution - for everyone who will need to solve the same problem. Perhaps this solution will be useful for anyone who needs it.

<?php
// snippet of xml temple
$xml = <<<XML
<item date="%s" status="%s">
  <name>%s</name>
</item>
XML;

// prepare snippet
$xmlSnippet = sprintf($xml, "2022-11-21", 0, "Foo Bar");

// new DOMDocument
$dom = new DOMDocument;
$dom->preserveWhiteSpace = 0;
$dom->formatOutput = 1;

// load of .xml file content and load to DOMDocument object
$file = simplexml_load_file("xml.xml");
$dom->loadXML($file->asXML());

// creating of fragment from snippet
$fragment = $dom->createDocumentFragment();
$fragment->appendXML($xmlSnippet);

//append the snippet to the DOMDocument
// and save it to the xml.xml file
$dom->documentElement->appendChild($fragment);
$dom->save("xml.xml");
?>

Result: Result

2 Comments

Why do you load it into a SimpleXML first and not into the DOMDocument directly?
You're right. I don't know why I didn't think about it. @ThW

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.