Long xml file editing

I’m coding a php file that opens up an xml file and adds/removes elements to it. Loading the xml file leaves me with a fairly large variable storing it. One problem I’m having is adding text/elements to points in the middle of the file. Here’s the loading code so far:
[php]$rss = “snakebit.xml”;
$file = fopen($rss,‘r’) or die(“Error opening file!”);
$data = fread($file, filesize($rss));
fclose($file);
$data = str_replace("","",$data);
$data = $data . “\n” .
“” . $_POST[‘title’] . “\n” .
“” . $_POST[‘description’] . “\n” .
“” . $_POST[‘teacher’] . “\n” .
“” . $_POST[‘class’] . “\n” .
“” . $_POST[‘date’] . “\n” .
“\n” . “”;
$file = fopen($rss,‘w’) or die(“Error opening file!”);
fwrite($file, “$data”);
fclose($file);
echo ‘Thank you! Your assignment has been uploaded!’;[/php]
As you noticed, I have to add the whole item element before the element, and then replace the entire file. This is very ineffective once the file becomes a large database, especially when I need to remove elements from the center. Is there a better way to insert/delete text into the middle of a string?

Have you looked into possibly using PHP’s SimpleXML class instead?

http://www.php.net/manual/en/simplexml.examples-basic.php

Wow, never knew that existed. That’s astoundingly easier. Thanks

PHP has many classes available :slight_smile: I put together an example to get you started.

[php]
$xml_string = "


This is a title
This is a description
This is a date


";

$sxe = new SimpleXMLElement($xml_string);

$new_item = $sxe->addChild(‘item’);
$new_item->addChild(‘title’, ‘This is another title’);
$new_item->addChild(‘description’, ‘This is another description’);
$new_item->addChild(‘date’, ‘This is another date’);

echo $sxe->asXML();
[/php]

Also, note that you can specify a path or URL instead of a string. So there is no need to fopen the file.

See:
http://www.php.net/manual/en/simplexmlelement.construct.php

[php]$sxe = new SimpleXMLElement(‘http://example.org/document.xml’, NULL, TRUE);[/php]

Hm… for some odd reason, if I add a child named ‘title’, it does something weird. According to Chrome’s debug, it for some reason has a css rule:title { display: none; }
I have no css file written and the css rule only applies when it is named ‘title’ exactly, no matter the order of childs.

So any element at all named for some reason doesn’t show up when echo’ing the xml file. From a loaded file, coded string, or added element/child.

Actually, it is because the XML tags are being seen as HTML tags. You could do this to preview the raw output.

[php]
echo “

”;
echo htmlspecialchars($sxe->asXML());
echo “
”;
[/php]

OR you could send your headers first.

[php]
header(“Content-type: text/xml; charset=utf-8”);
echo $sxe->asXML();
[/php]

I would also recommend using Firefox (with Firebug add-on) for development :slight_smile:

Thanks, this helps a ton. Still have one problem though. When I unset and delete nodes I run into a problem. When I unset all the elements within an element, the parent element turns into: “<[NodeName]/>”. Example: if the parent node was , upon the removal of all elements within , it turns into simply . Here’s the code:
[php]<?php
if($_POST[‘teacher’] != ‘’ && $_POST[‘class’] != ‘’){
$xml = simplexml_load_file(‘teacher_xmls/’ . $_POST[‘teacher’] . ‘.xml’);
echo $_POST[‘assignment’] . “”;
echo $xml->xpath(‘item’)[$_POST[‘assignment’]]->title . “”;
unset($xml->xpath(‘item’)[$_POST[‘assignment’]]->title);
unset($xml->xpath(‘item’)[$_POST[‘assignment’]]->description);
unset($xml->xpath(‘item’)[$_POST[‘assignment’]]->date);
unset($xml->xpath(‘item’)[$_POST[‘assignment’]]->class);
unset($xml->xpath(‘item’)[$_POST[‘assignment’]]);
echo $xml->xpath(‘item’)[$_POST[‘assignment’]]->title . “”;
$data = $xml->asXML();

$file = fopen(‘teacher_xmls/’ . $_POST[‘teacher’] . ‘.xml’,‘w’) or die(“Error opening file!”);
fwrite($file, $data);
fclose($file);

echo ‘Thank you! Your assignment has been deleted!’;
}else{
echo ‘There was a problem with the deletion!’;
}
//echo ‘’;
?>[/php]
The loaded xml file is like:

<?xml version="1.0"?> <rss><item><title>Title!</title><description>Description!</description><class>0</class><date>2012-10-24</date></item></rss>
Afterwards, the xml looks like:

<rss><item/></rss>

I’ve also tried just unsetting the whole element, but that did absolutely nothing. The program should work with the “” tag sitting there, but it takes up space, ruins organization, and is just annoying. I can’t seem to unset the tag.

Thanks for the help!

What is the value of $_POST[‘assignment’]? Is it supposed to be an array key?

It’s the value that’s used to identify the correct element. It’s assign to select list options through javascript. It’s not the problem, seeing as the internal elements (,,etc.) are removed from the correct element (if there are 2+).

Here is what I would do. Use the DOMElement to remove the parent node. I’m not sure what the $_POST[‘assignment’] value is or how you use it, but if you include it as an ID in the XML it would be simple to match like this:

<rss>
	<item>
		<assignment>1</assignment>
		<title>Title!</title>
		<description>Description!</description>
		<class>0</class>
		<date>2012-10-24</date>
	</item>
	<item>
		<assignment>999</assignment>
		<title>Title!</title>
		<description>Description!</description>
		<class>0</class>
		<date>2012-10-24</date>
	</item>
</rss>

[php]
$xml_file = ‘test.xml’;
$sxe = new SimpleXMLElement($xml_file, null, true);

// Loop items
foreach($sxe->item as $item) {
// Match assignment value from $item
if ((int) $item->assignment === 999) {
$dom = dom_import_simplexml($item); // create a DOMElement from SimpleXMLElement
$dom->parentNode->removeChild($dom); // remove the parent node of $item using DOMElement
}
}
$sxe->asXML($xml_file); // specifying $xml_file here will do the save for you so fopen is not necessary
[/php]

If you do know the array key that you need to remove, you can remove the loop & the match:

[php]
$xml_file = ‘test.xml’;
$sxe = new SimpleXMLElement($xml_file, null, true);
$dom = dom_import_simplexml($sxe->item[1]); // create a DOMElement from SimpleXMLElement
$dom->parentNode->removeChild($dom); // remove the parent node of $item using DOMElement
$sxe->asXML($xml_file); // specifying $xml_file here will do the save for you so fopen is not necessary
[/php]

Thanks, I had seen the use of DOM elements but wasn’t sure how to approach it. I had to replace the constant with: php $_POST[‘assignment’][/php] and it worked perfectly.

Sponsor our Newsletter | Privacy Policy | Terms of Service