Getting node Value of last Child - php

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;

Related

PHP - DOMXpath does not return any nodes when it should

I am pulling HTML from Selenium, and then extracting data from the HTML using Xpaths.
This is the Xpath:
/html/body/div[2]/div[1]/div/div/div/div/ul/li/div[1]/h3/a
This is my code:
$data = $webdriver->getPageSource();
d($data, $urltemplate);
$doc = new DOMDocument();
$doc->loadHTML($data);
$xp = "/html/body/div[2]/div[1]/div/div/div/div/ul/li/div[1]/h3/a";
$xpatho = new DOMXpath($doc);
$elementsn = $xpatho->query($xp);
d(get_class($elementsn),$elementsn->count(),$xp,$name);
// d() is a custom function like var_dump().
I always get $elementsn->count() = 0.
This is $data:
https://pastebin.com/ahuvkJfN
I am trying to extract those strings like "NAD M10 BLUOS...", "NAD M12 DIRECT DIGITAL..." and so on...
I saved the HTML into a file, and opened it in my browser. I am attaching screenshot of what data I was looking to retrieve (highlighted in blue):
Basically, the HTML page is a product listing, and I am looking to extract all the product names. To confirm, I used Chrome Developer tools, and used the copy full Xpath function. I have the following Xpaths for some of the product names:
/html/body/div[2]/div[1]/div/div/div/div/ul/li[1]/div[1]/h3/a
/html/body/div[2]/div[1]/div/div/div/div/ul/li[3]/div[1]/h3/a
I would guess that this would generalise to:
/html/body/div[2]/div[1]/div/div/div/div/ul/li/div[1]/h3/a
However, I keep on getting a DOMNodeList with count = 0. Why is this so, and how can I check what the error is, if any?
P.S.: This is the original webpage: http://lenbrook.com.sg/3-shop-by-brand#/page-4/price-49-8667
Try changing your $xp
$xp = '//a[#class="product_link"]/text()'

Having trouble targeting with DOM Xpath

I know there are many questions here about DOM traversal with XPATH. I have done a good amount of research before bringing my question here, but I am still having an issue. I'm trying to pull the number of downloads for a given app on the android market. So for instance if the app were the stack exchange app, I would want to pull the numbers: 50,000 - 100,000 from this page:
https://play.google.com/store/apps/details?id=com.stackexchange.marvin
I am attempting to target the div with an itemprop of "numDownloads" to little avail. I have no trouble targeting other items on page I have tried (various classes, etc) but this specific item never returns results. I have checked to make sure the value is, in fact, in the source and not being inserted by JS. Here is my code:
// Load up the document so we can parse the dom
$dom = new DomDocument();
$dom->loadHTML($this->html);
// XPath so we can do some specific searches
$finder = new DomXPath($dom);
// Find all the number of downloads item on page
$installs = $finder->query("//*[#itemprop='numDownloads']");
echo "<pre>"; var_dump($installs); echo "</pre>";
foreach($installs as $install) {
echo "<pre>"; var_dump($install->nodeValue); echo "</pre>";
}
Any suggestions would be greatly appreciated!
Actually you are already on the right track.
$url = 'https://play.google.com/store/apps/details?id=com.stackexchange.marvin';
$contents = file_get_contents($url);
$dom = new DOMDocument();
#$dom->loadHTML($contents);
$finder = new DomXPath($dom);
$installs = $finder->query("//div[#itemprop='numDownloads']");
// directly point it to a div since it is a div
foreach($installs as $install) {
echo $install->nodeValue; // 50,000 - 100,000
}

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.

Read XML file and write to a php array/file

I need to update the country list of my website and I want to automate the process. Country list can be found here
http://www.iso.org/iso/country_codes...code_lists.htm // Edit : Can't find the good link...
I tried it this way –
http://www.w3schools.com/php/php_xml_parser_expat.asp (PHP XML Expat Parser)
However, this didn't seem to work well as I was confused where to actually 'get' the data and print it to my own array for later use.
Now I want to try it using XML DOM.
Just want to check with everyone, if I had a simple XML file to read, that contained a country code and country name as follows:
<Entry>
<Country_name>AFGHANISTAN</Country_name>
<Code_element>AF</Code_element>
</Entry>
I want to read this file (DOM method), and then feed the data into a separate file/array of mine that will be accessed by my website. What PHP xml functions would YOU use/recommend to do this simple task?
Any help in this regards is appreciated.
Use SimpleXML
how about
$dom = new DOMDOcument();
$dom->loadXML($xml);
$xpath = new DOMXpath($dom);
$res = $xpath->query("/CODE");
$allres = array();
foreach($res as $node){
$result = array();
$result['country'] = ($node->getElementsByTagName("Country_name")->item(0)->nodeValue);
$result['code'] = ($node->getElementsByTagName("Code_element")->item(0)->nodeValue);
$allres[] = $res
}
in the end $allres array would contain all your country codes and names

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