Php retrieve XML elements and edit file on server - php

I've searched and tried a number of examples and answers I've found here, but I think my requirements are quite specific and I haven't been able to find an answer that's worked for me so far... Bodging a number of answers together hasn't worked either!
Aim - Update the hosplist_divert value of the same element that contains a specific name tag.
The XML file is hosted in a sperate folder to the php page, in those case at /data/hospitals2.xml
My XML is like so:
<Document>
<Placemark>
<name>UHSM Wythenshawe</name>
<hosplist_divert>1</hosplist_divert>
</Placemark>
</Document>
There are approx 50 Placemark entries in the file.
So far I am only able to return all the hospital names from the file with,
// Create the SXE object
// You can read from file using the simplexml_load_file function
$url = "http://www.patientpathfinder.co.uk/user/nwasdos/data/hospitals2.xml";
$sxe = new SimpleXMLElement($url, NULL, TRUE);
$sxe->registerXPathNamespace('hospital','http://earth.google.com/kml/2.2');
// Fetch the right HOSPITAL using XPATH
// hospital name stored in Document/Placemark/name
// dovert status stored in Document/Placemark/hosplist_divert
//trying to find above values for UHSM Wythenshawe
$result=$sxe->xpath('//hospital:name[.="UHSM Wythenshawe"]/parent::*');
foreach ($result as $hospital)
{
echo $hospital . "<br>";
}
// Update the values you want
//$target_hosp[0]->hosplist_divert = 'ON DIVERT';
// Store the updated values in the $xml variable
//$xml = $sxe->asXML();
// Print the updated XML
//echo $xml;
}
It took me about half a day to realise that I needed to define the namespace, but haven't really had time to understand why the namespace is required and would be happy to remove it from the XML file in. Favour of a working solution.
Thanks to all that contribute,
Nick

Related

unset() Not Working For XML

Currently I am using unset() for removing a parent node in simpleXML, and writing it back to the XML file
I tried this code and it was working a while ago, after cleaning my code I can't find why it doesn't work all of the sudden,
The debugging approaches I took: the file can be accessed, I can enter the loop and if statement, the file gets saved (notepad++ asks me to reload), but the <systemInfo></systemInfo> does not get deleted
Here is my sample Code:
$userorig = $_POST['user'];
$userinfos = simplexml_load_file('userInfo.xml'); // Opens the user XML file
foreach ($userinfos->userinfo->account as $account)
{
// Checks if the user in this iteration of the loop is the same as $userorig (the user i want to find)
if($account->user == $userorig)
{
echo "hello";
$rootSystem = $account->systemInfo;
unset($rootSystem);
}
}
$userinfos->saveXML('userInfo.xml');
My XML File:
<userinfos>
<userinfo>
<account>
<user>TIGERBOY-PC</user>
<toDump>2014-03-15 03:20:44</toDump>
<toDumpDone>0</toDumpDone>
<initialCheck>0</initialCheck>
<lastChecked>2014-03-16 07:12:17</lastChecked>
<alert>1</alert>
<systemInfo>
... (many nodes and sub nodes here) ...
</systemInfo>
</account>
</userinfo>
</userinfos>
Rather than iterating over the whole xml, use xpath to select the node:
$userorig = $_POST['user'];
$userinfos = simplexml_load_file('userInfo.xml'); // Opens the user XML file
$deletethisuser = $userinfos->xpath("/userinfos/userinfo/account[user = '$userorig']/systemInfo")[0];
unset($deletethisuser[0]);
Comments:
the [0] in the xpath... line requires PHP >= 5.4, in case you are running on a lower version, either update or go:
$deletethisuser = $userinfos->xpath("/userinfos/userinfo/account[user = '$userorig']/systemInfo");
unset($deletethisuser[0][0]);
Advised reading: hakre's answer in this thread: Remove a child with a specific attribute, in SimpleXML for PHP
It worked again, sorry, I did not know why it worked, I keep running it on multiple instances, and now it works, the program has weird behavior, but tried it for around 15 tries, it did its job

XML file content not updating using PHP

Each time I run the code, file updates and I can see the file last edited date and time are updated but the content in the XML file is not updated.
I just tried to update the following XML Code
<?xml version="1.0" encoding="utf-8"?>
<topcont>
<sitenondualtraining>
<title>The Heart of Awakening</title>
<descripition>nondual</descripition>
<link>www.test.com/post/latestpost</link>
</sitenondualtraining>
</topcont>
using PHP code
$topcont = new DOMDocument();
$topcont->load("http://fenner.tk/topcont.xml");
$topcont->topcont->sitenondualtraining->title = 'test';
$topcont->sitenondualtraining->descripition = $_POST['nd2'];
$topcont->sitenondualtraining->link = $_POST['nd3'];
$topcont->Save("topcont.xml");
I also tried
$topcont = new SimpleXmlElement('http://fenner.tk/topcont.xml',null, true);
$topcont->sitenondualtraining->title = $_POST['nd1'];
$topcont->sitenondualtraining->descripition = $_POST['nd2'];
$topcont->sitenondualtraining->link = $_POST['nd3'];
$topcont->asXml('topcont.xml');
But none of these are working. Can anyone point where the issue is? Thanks.
File permission are set to 777 but still not working
NO ERRORS BUT WARNINGS ARE
Warning: Creating default object from empty value in /home/fenner/public_html/topads.php on line 20
Warning: Creating default object from empty value in /home/fenner/public_html/topads.php on line 21 /home/fenner/public_html/
Using DomDocument, you were almost there. You can do it like this:
$topcont = new DOMDocument();
$topcont->load("topcont.xml");
$topcont->getElementsByTagName("title")->item(0)->nodeValue = $_POST['nd2'];
$topcont->getElementsByTagName("description")->item(0)->nodeValue = $_POST['nd2'];
$topcont->getElementsByTagName("link")->item(0)->nodeValue = $_POST['nd3'];
$topcont->save("topcont.xml");
Just remember to sanitize your inputs before storing your data ;)
Also worth looking into is creating cdata sections and using replaceData, depending on what you intend to store in each node.
EDIT
In response to your comment below, you might want to change your xml structure a little if you are going to be handling multiple child nodes. This way it is easier to loop through and update the node you are interested in. You will see below that I moved 'sitenondualtraining' and 'siteradiantmind' to be id's of an 'item" node, though you could easily change this to something like <site id="nodualtraining> if that's more like what you were looking for.
<?xml version="1.0" encoding="utf-8"?>
<topcont>
<item id="sitenondualtraining">
<title>test</title>
<description>hello test</description>
<link>hello</link>
</item>
<item id="siteradiantmind">
<title>The Heart of Awakening</title>
<description>radiantmind</description>
<link>www.radiantmind.com/post/latestpost</link>
</item>
</topcont>
Your PHP code would then be something like this, again this is quite basic and could be tidied up, but is a good start:
$items = $topcont->getElementsByTagName("item");
// loop through each item
foreach ($items as $item) {
$id = $item->getAttribute('id');
// check the item id to make sure we edit the correct one
if ($id == "sitenondualtraining") {
$item->getElementsByTagName("title")->item(0)->nodeValue = $_POST['nd1'];
$item->getElementsByTagName("link")->item(0)->nodeValue = $_POST['nd2'];
$item->getElementsByTagName("description")->item(0)->nodeValue = $_POST['nd3];
}
}
If you were feeling a little adventurous, you could have a look at xpath and xpath query, you can find some sample code in most php docs to get you started and the comments from other users can be helpful as well.
For reference: getAttribute, getElementsByTagName.

Getting node Value of last Child

This question may seem very stupid, but I am not able to find much help on how to find the node value of the last child using PHP, even though it's a piece of cake with JS.
This is what my XML currently looks like:
<?xml version="1.0"?>
<files>
<file>.DS_Store</file>
<file>ID2PDF_log_1.xml</file>
<file>ID2PDF_log_12.xml</file>
<file>ID2PDF_log_15.xml</file>
</files>
Here's the php code:
$filename = 'files.xml'; //my xml file name
$dom = new DomDocument();
$dom->load($filename);
$elements = $dom->getElementsByTagName('file');
echo $elements->lastChild(); // This is obviously not working
/*I get an error that I am trying to access an undefined method in DOMNodeList. Now, I know
that lastChild is a property of DOMNode. But I can't figure out how I can change my code to
get this to work.*/
I am trying to echo out
ID2PDF_log_15.xml
Can anyone show me how to get this done?
P.S.: I don't want to change the xml file structure because I am creating it through a script and I am a lazy programmer. But, I did do my research to get this. Didn't help.
I did try getting the number of elements in the node 'file' and then using item(#), but that didn't seem to work either.
Thanks
SOLUTION
$filename = 'files.xml';
$dom = new DomDocument();
$dom->load($filename);
$elements = $dom->getElementsByTagName('file')->length;
echo 'Total elements in the xml file:'.$elements."\n";
$file = file_get_contents('files.xml');
$xml = simplexml_load_string($file);
$result = $xml->xpath('file');
echo "Last element".$result[$elements-1]."\n";
I'll make this neater a little later. But, just thought that I should share the answer anyway any new users in the future.
This should work:
$elements->xpath('root/child[last()]');
Read up about xpath
Alternatively I would suggest counting the number of elements, and then targeting the last element using that count:
$file_count = $elements->getElementsByTagName('file')->length;
$elements[$file_count];
i did it this way:
$elements = $dom->getElementsByTagName('file')->item(0);
echo $elements->lastChild->nodeValue;

PHP: Parse XML with SimpleXML

I'm having issues attempting to parse an XML file I'm pulling in from another site with SimpleXML. I need to display the rent for certain properties. However, I only want to display the rent for certain properties. I've never seen an XML file structured in this manner: http://dl.dropbox.com/u/1925679/example.xml
First, how would I parse through this file based on
Property->PropertyID->MITS:Identification->MITS:PrimaryID
Then, echo out the Property->Floorplan->MarketRent(Min and Max) based on an ID?
TIA!!!!
// get all properties
$properties = $xml->xpath('//Property');
// get document namesapces in prefix => uri format
$namespaces = $xml->getNamespaces(true);
foreach($properies as $property)
{
// get namespaced nodes
$identification = $property->PropertyID->children($namespaces['MITS']);
$id = $identification->children($namespaces['MITS'])->PrimaryID;
// do your check id is an expected value or whatever and if so then...
foreach($property->Floorplan as $floorplan){
{
echo $floorplan->MarketRent['min'];
echo $floorplan->MarketRent['max'];
}
}
You could probably com up with an xpath query to ONLY select properties with a given id or set of ids straight away so then you would only have to loop over them and invoke the floorplan loop but ill leave that to your investigation :-) I will say though if you go that route, you will need to register the namespaces with xpath i think. Pretty sure thats not automatic.

Updating the XML file using PHP script

I'm making an interface-website to update a concert-list on a band-website.
The list is stored as an XML file an has this structure :
I already wrote a script that enables me to add a new gig to the list, this was relatively easy...
Now I want to write a script that enables me to edit a certain gig in the list.
Every Gig is Unique because of the first attribute : "id" .
I want to use this reference to edit the other attributes in that Node.
My PHP is very poor, so I hope someone could put me on the good foot here...
My PHP script :
Well i dunno what your XML structure looks like but:
<gig id="someid">
<venue></venue>
<day></day>
<month></month>
<year></year>
</gig>
$xml = new SimpleXmlElement('gig.xml',null, true);
$gig = $xml->xpath('//gig[#id="'.$_POST['id'].'"]');
$gig->venue = $_POST['venue'];
$gig->month = $_POST['month'];
// etc..
$xml->asXml('gig.xml)'; // save back to file
now if instead all these data points are attributes you can use $gig->attributes()->venue to access it.
There is no need for the loop really unless you are doing multiple updates with one post - you can get at any specific record via an XPAth query. SimpleXML is also a lot lighter and a lot easier to use for this type of thing than DOMDOcument - especially as you arent using the feature of DOMDocument.
You'll want to load the xml file in a domdocument with
<?
$xml = new DOMDocument();
$xml->load("xmlfile.xml");
//find the tags that you want to update
$tags = $xml->getElementsByTagName("GIG");
//find the tag with the id you want to update
foreach ($tags as $tag) {
if($tag->getAttribute("id") == $id) { //found the tag, now update the attribute
$tag->setAttribute("[attributeName]", "[attributeValue]");
}
}
//save the xml
$xml->save();
?>
code is untested, but it's a general idea

Categories