I am trying to update an XML file if a value passed matches the parent value. Basically once a minute a series of IP Addresses are pinged and the result is passed to my php script like this: http://ipaddress/presence.php?ip=192.168.0.55&present=1.
XML (presence.xml):
<?xml version="1.0" encoding="UTF-8"?>
<Presence>
<Person IP="192.168.0.55">
<Name>Bob</Name>
<Present>1</Present>
<LastSeen>14/09/2014 01:48:43 pm</LastSeen>
</Person>
<Person IP="192.168.0.56">
<Name>John</Name>
<Present>0</Present>
<LastSeen>13/09/2014 08:32:19 pm</LastSeen>
</Person>
</Presence>
PHP (presence.php):
<?php
$ip = $_REQUEST['ip'];
$present = $_REQUEST['present'];
// Write latest data to XML file
$Presence = simplexml_load_file('presence.xml');
foreach ($Presence->xpath('//Person') as $Person) {
if ($Person[#IP] == $ip) {
$Person->Present = $present;
}
else {}
}
?>
The code above I had hoped would update the <Present> tag with the value passed in the URL. Yet nothing happens, I don't get any errors in the log file. I did have the $present value inside the IF statement written in the wrong case initially which did throw an error regarding undefined variable, which indicated the code worked as far as the IF statement.
Any help appreciated, I have looked at various Q & As on Stackoverflow which is how I got this far, but can't figure this out. Once I have cleared this hurdle I will hopefully be able to add the code to update the <LastSeen> tag in the XML.
The url needs to be formatted correctly (replace the $ with &):
http://ipaddress/presence.php?ip=192.168.0.55&present=1
Edit
Make sure you save it after you make modifications
$Presence->asXML('presence.xml');
Try:
foreach ($Presence->Person as $Person) {
if ($Person->attributes()->IP == $ip) {
$Person->Present = $present;
}
}
Also, make sure you're actually getting an XML string (in the format you posted), just in case your input isn't quite what you expect.
Related
Im trying to load search result from an library api using Search and Retrieve via URL (SRU) at : https://data.norge.no/data/bibsys/bibsys-bibliotekbase-bibliografiske-data-sru
If you see the search result links there, its looks pretty much like XML but when i try like i have before with xml using the code below, it just returns a empty object,
SimpleXMLElement {#546}
whats going on here?
My php function in my laravel project:
public function bokId($bokid) {
$apiUrl = "http://sru.bibsys.no/search/biblio?version=1.2&operation=searchRetrieve&startRecord=1&maximumRecords=10&query=ibsen&recordSchema=marcxchange";
$filename = "bok.xml";
$xmlfile = file_get_contents($apiUrl);
file_put_contents($filename, $xmlfile); // xml file is saved.
$fileXml = simplexml_load_string($xmlfile);
dd($fileXml);
}
If i do:
dd($xmlfile);
instead, it echoes out like this:
Making me very confused that i cannot get an object to work with. Code i present have worked fine before.
It may be that the data your being provided ha changed format, but the data is still there and you can still use it. The main problem with using something like dd() is that it doesn't work well with SimpleXMLElements, it tends to have it's own idea of what you want to see of what data there is.
In this case the namespaces are the usual problem. But if you look at the following code you can see a quick way of getting the data from a specific namespace, which you can then easily access as normal. In this code I use ->children("srw", true) to say fetch all child elements that are in the namespace srw (the second argument indicates that this is the prefix and not the URL)...
$apiUrl = "http://sru.bibsys.no/search/biblio?version=1.2&operation=searchRetrieve&startRecord=1&maximumRecords=10&query=ibsen&recordSchema=marcxchange";
$filename = "bok.xml";
$xmlfile = file_get_contents($apiUrl);
file_put_contents($filename, $xmlfile); // xml file is saved.
$fileXml = simplexml_load_string($xmlfile);
foreach ( $fileXml->children("srw", true)->records->record as $record) {
echo "recordIdentifier=".$record->recordIdentifier.PHP_EOL;
}
This outputs...
recordIdentifier=792012771
recordIdentifier=941956423
recordIdentifier=941956466
recordIdentifier=950546232
recordIdentifier=802109055
recordIdentifier=910941041
recordIdentifier=940589451
recordIdentifier=951721941
recordIdentifier=080703852
recordIdentifier=011800283
As I'm not sure which data you want to retrieve as the title, I just wanted to show the idea of how to fetch data when you have a list of possibilities. In this example I'm using XPath to look in each <srw:record> element and find the <marc:datafield tag="100"...> element and in that the <marc:subfield code="a"> element. This is done using //marc:datafield[#tag='100']/marc:subfield[#code='a']. You may need to adjust the #tag= bit to the datafield your after and the #code= to point to the subfield your after.
$fileXml = simplexml_load_string($xmlfile);
$fileXml->registerXPathNamespace("marc","info:lc/xmlns/marcxchange-v1");
foreach ( $fileXml->children("srw", true)->records->record as $record) {
echo "recordIdentifier=".$record->recordIdentifier.PHP_EOL;
$data = $record->xpath("//marc:datafield[#tag='100']/marc:subfield[#code='a']");
$subData=$data[0]->children("marc", true);
echo "Data=".(string)$data[0].PHP_EOL;
}
I have a problem. My PHP script not working and I dont know why. This is XML file:
http://itoffice.sk/toto.xml
And this is my PHP code for read XML:
$xml = simplexml_load_file("toto.xml") or die("feed sa nepodarilo načítať");
$id = $xml->Zbozi['kod_zbozi'];
echo $id;
This not working. I need show and write into MySQL all attributes of <Zbozi>
<Zbozi> example:
<Zbozi diffgr:id="Zbozi1" msdata:rowOrder="0" kod_zbozi="DL139A" popis="HP DMS-59 to Dual DVI Cable Kit,accessory" part_number="DL139A" zaruka="24" dostupnost="false" dph="20" cena="29.23" cenaEU="35.34" snimek="DL139A/06_s.jpg" kod_vyrobce="093-001453" kod_kategorie="PC STOLNÍ POČÍTAČE" kategorie="Stolné počítače" kod_podkategorie="PŘÍSLUŠENSTVÍ ZN PC" podkategorie="Príslušenstvo značkových PC" typ="0" aut_poplatek="0.000" rema="0.000" sam_neprodejne="0" sn_vydej="false" ean="808736662901" doprodej="false">
Help me please. Thanks.
The reason your script was not working, is because you weren't following the XML tree properly. As you can see, your XML's structure looks like this:
<diffgr:diffgram>
<Cenik>
<Zbozi></Zbozi>
...
<Zbozi></Zbozi>
</Cenik>
</diffgr:diffgram>
Therefore you would have to follow that tree, and then loop for the Zbozi elements in order to get all of their attributes.
Take a look at this code:
$xml = simplexml_load_file('http://itoffice.sk/toto.xml');
$zbozi = $xml->children('diffgr', TRUE)->diffgram->children()->Cenik->Zbozi;
$id_arr = array();
foreach ($zbozi as $zbozi_element)
{
$id_arr[] = (string) $zbozi_element['kod_zbozi'];
}
First we load the XML file, nothing new there. But in the second line, we are traversing down the XML file. First we set the prefix namespace to diffgr (because of the semicolon in diffgr:diffgram), then we simply find the Zbozi elements, and loop for them.
You can see that in the loop I've added all of the kod_zbozi attribute values into an array. You can really do anything you'd like with that information at this point, this was just to get you started.
I am trying to search for a php variable in an xml file using xpath, but failing miserably. It works with a hard coded value, so I am nearly there..
<visitors>
<detail>
<id>876867</id>
<name>Bob McHaggis</name>
<email>bob#gmail.com</email>
</detail>
<detail>
<id>897987</id>
<name>Mark McBob</name>
<email>mark#gmail.com</email>
</detail>
</visitors>
<?php $sxe = simplexml_load_file("/CaptivePortal/visitors.xml");
foreach($sxe->xpath('//visitors/detail') as $item){
$row = simplexml_load_string($item->asXML());
$v = $row->xpath('//id[. ="'.$_COOKIE["judsons"].'"]');
} echo $v[0]; ?>
This works great checks for an id against the id stored in the cookie. But based on that value being found how do I access the name and email for the key matched?
Found & matched: 897987
I want to echo the name and email to, so based on that is Mark McBob & mark#gmail.com
My initial advice would be to take a good few minutes to (re-)read through the SimpleXML Basic Usage page in the PHP manual.
For selecting a single item within the XML file, there is no need at all to loop over anything. The example code below, and why it is different from yours, should become clear after familiarising yourself with the page mentioned above.
<?php
$search_id = (int) $_COOKIE["judsons"];
$visitors = simplexml_load_file("/CaptivePortal/visitors.xml");
$details = $visitors->xpath("detail[id='$search_id']");
if (empty($details)) {
echo "No details found for '$search_id'.";
} else {
$detail = $details[0];
$name = (string) $detail->name;
$email = (string) $detail->email;
echo "$name's email is $email";
}
The idea above is that $details will be an array containing hopefully just one <detail> element. It could be an empty array if no <detail> was found with the specified <id>, which is what the if(empty(…)) checks for. If the $details array is not empty, we're really only interested in the first one ($details[0]).
To access the information available within the <detail>, as explained on the "basic usage" page, the elements can be accessed with normal object property syntax ($detail->name). Doing so returns an object for that item (e.g. the <name>), so to get at the value as a string the object is type cast using (string).
You're actually doing quite a bit you don't need to there. For one thing, you don't need the loop. For another, inside your loop, you convert the context XML into a string (::asXML()), then convert it back into XML (simplexml_load_string()).
All you need is:
$xml = "<visitors><detail><id>876867</id><name>Bob McHaggis</name><email>bob#gmail.com</email></detail><detail><id>897987</id><name>Mark McBob</name><email>mark#gmail.com</email></detail></visitors>";
$sxe = simplexml_load_string($xml);
$row = $sxe->xpath('detail[id = '.$_COOKIE["judsons"].']');
That gets you the row. To extract part of it:
$name = $row[0]->xpath('name');
echo $name[0]; //Mark McBob
I'm trying to get a product list for a client from a webservices xml file over to an SQL databse using a little php script, but I can't seem to get it to work.
The relevant code is as follows:
$c = 0;
...
$xml = simplexml_load_file($completeurl);
$listingsArray = $xml->listings->listing;
foreach($listingsArray as $listing){
$addition[0] = $listing[$c]->type;
$addition[1] = $listing[$c]->condition;
//etcetera
c = c + 1;
}
The XML file is formated like:
<inventory>
<listings>
<listing>
//tags for type, condition, etc
</listing>
</listings>
</inventory>
$completeurl is a string that contains the url of the xml file
$addition is an array that's defined earlier in the code
I've been working on this for a while now, but I can't seem to figure out where the error is in my code. The problem that I'm having is that $listingsArray should have close to 100 elements in it, but is constantly coming up with 0. Anybody see what I'm doing wrong?
EDIT: I tried changing
$listingsArray = $xml->listings->listing;
to
$listingsArray = $xml->listings;
But empty strings are still being written to the $addition array. A var_dump of listingsArray show that all of the information is in there, though.
If you want each listing i believe you are going a child too deep.
$listingsArray = $xml->listings->listing;
shoudl be
$listingsArray = $xml->listings;
foreach($listingsArray as $listing){
$addition[0] = $listing[$c]->type;
$addition[1] = $listing[$c]->condition;
//etcetera
}
additionally what is $c? It also helps to post your exact errors. When debugging inserting var_dumps is extremely helpful. If you think the probelm is $listingArray
print it out and see if it contains the data you want.
changing
$listingsArray = $xml->listings->listing;
to
$listingsArray = $xml->listings;
Should solve the issue. You set $listingsArray to the array of listings, then the foreach tries to go down another level
I'm trying to loop through multiple <LineItemInfo> products contained within a <LineItems> within XML I'm parsing to pull product Ids out and send emails and do other actions for each product.
The problem is that it's not returning anything. I've verified that the XML data is valid and it does contain the necessary components.
$itemListObject = $orderXML->getElementsByTagName('LineItemInfo');
var_dump($itemListObject->length);
var_dump($itemListObject);
The output of the var_dump is:
int(0)
object(DOMNodeList)#22 (0) {
}
This is my first time messing with this and it's taken me a couple of hours but I can't figure it out. Any advice would be awesome.
EDIT:
My XML looks like this... except with a lot more tags than just ProductId
<LineItems>
<LineItemInfo>
<ProductId href='[URL_TO_PRODUCT_XML]'>149593</ProductId>
</LineItemInfo>
<LineItemInfo>
<ProductId href='[URL_TO_PRODUCT_XML]'>149593</ProductId>
</LineItemInfo>
</LineItems>
Executing the following code does NOT get me the ProductId
$itemListObject = $orderXML->getElementsByTagName('LineItemInfo');
foreach ($itemListObject as $element) {
$product = $element->getElementsByTagName('ProductId');
$productId = $product->item(0)->nodeValue;
echo $productId.'-';
}
EDIT #2
As a side note, calling
$element->item(0)->nodeValue
on $element instead of $product caused my script's execution to discontinue and not throwing any errors that were logged by the server. It's a pain to debug when you have to run a credit card to find out whether it's functioning or not.
DOMDocument stuff can be tricky to get a handle on, because functions such as print_r() and var_dump() don't necessarily perform the same as they would on normal arrays and objects (see this comment in the manual).
You have to use various functions and properties of the document nodes to pull out the data. For instance, if you had the following XML:
<LineItemInfo attr1="hi">This is a line item.</LineItemInfo>
You could output various parts of that using:
$itemListObjects = $orderXML->getElementsByTagName('LineItemInfo');
foreach($itemListObjects as $node) {
echo $node->nodeValue; //echos "This is a line item."
echo $node->attributes->getNamedItem('attr1')->nodeValue; //echos "hi"
}
If you had a nested structure, you can follow basically the same procedure using the childNodes property. For example, if you had this:
<LineItemInfo attr1="hi">
<LineItem>Line 1</LineItem>
<LineItem>Line 2</LineItem>
</LineItemInfo>
You might do something like this:
$itemListObjects = $orderXML->getElementsByTagName('LineItemInfo');
foreach($itemListObjects as $node) {
if ($node->hasChildNodes()) {
foreach($node->childNodes as $c) {
echo $c->nodeValue .",";
}
}
}
//you'll get output of "Line 1,Line 2,"
Hope that helps.
EDIT for specific code and XML
I ran the following code in a test script, and it seemed to work for me. Can you be more specific about what's not working? I used your code exactly, except for the first two lines that create the document. Are you using loadXML() over loadHTML()? Are there any errors?
$orderXML = new DOMDocument();
$orderXML->loadXML("
<LineItems>
<LineItemInfo>
<ProductId href='[URL_TO_PRODUCT_XML]'>149593</ProductId>
</LineItemInfo>
<LineItemInfo>
<ProductId href='[URL_TO_PRODUCT_XML]'>149593</ProductId>
</LineItemInfo>
</LineItems>
");
$itemListObject = $orderXML->getElementsByTagName('LineItemInfo');
foreach ($itemListObject as $element) {
$product = $element->getElementsByTagName('ProductId');
$productId = $product->item(0)->nodeValue;
echo $productId.'-';
}
//outputs "149593-149595-"
XML tags tend to be lower-camel-case (or just "camel-case"), i.e. "lineItemInfo", instead of "LineItemInfo" and XML is case-sensitive, so check for that.