This is a small part of the XML file I am reading:
<hotel>
<Location>
<Identifier>D5023</Identifier>
<IsAvailable>true</IsAvailable>
<Availability>
<TimeStamp>2015-06-11T16:04:23.887</TimeStamp>
<Rooms>525</Rooms>
<Beds>845</Beds>
</Availability>
</Location>
<Location>
ect.
</Location>
</hotel>
Using XMLsimple I want to get the number of available rooms for location D5023 (and other locations). But because the Identifier is a child from the Location attribute I am struggling to get the right data.
This is what I came up with, but obviously this doesnt work
$hotel->Location->Identifier['D5023']->Availability->Rooms;
How can I get this right?
You can use SimpleXMLElement::xpath() to get specific part of XML by complex criteria, for example :
$xml = <<<XML
<hotel>
<Location>
<Identifier>D5023</Identifier>
<IsAvailable>true</IsAvailable>
<Availability>
<TimeStamp>2015-06-11T16:04:23.887</TimeStamp>
<Rooms>525</Rooms>
<Beds>845</Beds>
</Availability>
</Location>
<Location>
ect.
</Location>
</hotel>
XML;
$hotel = new SimpleXMLElement($xml);
$result = $hotel->xpath("/hotel/Location[Identifier='D5023']/Availability/Rooms")[0];
echo $result;
output :
525
Demo
there are more Location so you have too loop on :
foreach ($hotel->Location as $l) {
if ("D5023" === $l->Identifier) {
var_dump($l->Availability->Rooms);
}
}
you load your file and loop through the XML file and check the ID , don't forget to cast the xml from object to string so you can compare 2 strings to each other and not an object to a string.
if( $xml = simplexml_load_file("path_to_xml.xml",'SimpleXMLElement', LIBXML_NOWARNING) )
{
echo("File loaded ...");
// loop through XML
foreach ($xml->hotel as $hotel)
{
// convert the xml object to a string and compare it with the room ID
if((string)$hotel->Location->Identifier == "D5023")
{
echo("there are ".$hotel->Location->Availability->Rooms."Available room in this hotel");
}
}
}
else
echo("error loading file!");
hope that helps !
Related
I am trying to read an XML file in PHP, edit some values and save it back.
I do it by opening the XML file in php. I then convert it using SimpleXML into an array. After doing the manipulation needed, I am struggling in returning that array into the XML file in the same format due to how my XML elements are converted into attributes. Hence when I go from array to XML, my elements (which are attributes now) are saved as attributes in the updated XML file. I would like to know if it's possible to preserve XML elements when converting back from php array to XML.
A random XML example with two elements, lets call it myFile.xml
<XML>
<Project Element1 = 'some random value' Element2='Will be stored as attribute instead'>
</XML>
The php code I would run to convert it into an array
<?php
$xml = simplexml_load_file("myFile.xml") or die("Error: Cannot create object");
$arrayXML = json_decode(json_encode((array)$xml), TRUE);
$arrayXML["Project"]["attributes"]["Element1"] = "updated value"
// I will then run some array to XML converter code here found online
// took it from here https://stackoverflow.com/questions/1397036/how-to-convert-array-to-simplexml
function array_to_xml( $data, &$xml_data ) {
foreach( $data as $key => $value ) {
if( is_array($value) ) {
if( is_numeric($key) ){
$key = 'item'.$key; //dealing with <0/>..<n/> issues
}
$subnode = $xml_data->addChild($key);
array_to_xml($value, $subnode);
} else {
$xml_data->addChild("$key",htmlspecialchars("$value"));
}
}
}
$xml_data = new SimpleXMLElement();
array_to_xml($arrayNexus,$xml_data);
saving generated xml file;
$result = $xml_data->asXML('myFile.xml');
?>
Something like this would then generate an XML file like this
<XML>
<Project>
<attribute>
<Element1>updated value</Element1>
<Element2><Will be stored as attribute instead</Element2>
</attribute>
</Project>
</XML>
When the result I would like to have would be
<XML>
<Project Element1 = 'updated value' Element2='Will be stored as attribute instead'>
</XML>
I could write my own XML converter but if there exist already methods out there, can someone show me the way?
Don't convert the XML - you will loose data if you don't use specific formats like JsonML. It is much easier to use DOM. Use Xpath expressions to fetch the nodes and modify them.
$document = new DOMDocument();
$document->loadXML($xml);
$xpath = new DOMXpath($document);
// iterate the first 'Project' element
foreach($xpath->evaluate('(/XML/Project)[1]') as $project) {
// change the attribute value
$project->setAttribute('Element1', 'updated value');
}
echo $document->saveXML();
Output:
<?xml version="1.0"?>
<XML>
<Project Element1="updated value" Element2="Will be stored as attribute instead"/>
</XML>
Xpath
'XML' document element/XML
'Project' child elements/XML/Project
Limit to first found node(/XML/Project)[1]
This example uses the position in the result list as a condition but if the project has an id attribute you could use this to find the element: /XML/Project[#id="example-id"].
I have the following XML file:
<?xml version="1.0" encoding="UTF-8"?>
<root>
<person>
<id>1</id>
<name>Jane</name>
<surname>Smith</surname>
</person>
<person>
<id>2</id>
<name>John</name>
<surname>Doe</surname>
</person>
</root>
And I have the following CSV file:
id;phone
1;12345678
2;78903456
I work with PHP. I need to do with XML something like this:
Add a phone number element to the person where id is...
For example: Add a phone element with value 12345678 to the person element with id 1.
As the content of the XML will vary, it will probably be easier to XPath to find the entry you want to update...
$telephoneList = [["id"=> 1, "phone" => "12345678"],
["id"=> 2, "phone" => "78903456"]];
$xml = simplexml_load_file("a.xml");
foreach ( $telephoneList as $telephone) {
$person = $xml->xpath("//person[id={$telephone['id']}]");
if ( count($person) == 1 ) {
$person[0]->addChild("phone", $telephone['phone']);
}
}
echo $xml->asXML();
This tries to find the <person> element with an <id> with the value from the csv. If this is found, it will add in the phone number using addChild()
It's just a case of reading in the CSV file and process it as above.
With SimpleXML, you can use the addChild() method.
$file = 'xml/config.xml';
$xml = simplexml_load_file($file);
$galleries = $xml->galleries;
$gallery = $galleries->addChild('gallery');
$gallery->addChild('name', 'a gallery');
$gallery->addChild('filepath', 'path/to/gallery');
$gallery->addChild('thumb', 'mythumb.jpg');
$xml->asXML($file);
Be aware that SimpleXML will not "format" the XML for you, however going from an unformatted SimpleXML representation to neatly indented XML is not a complicated step and is covered in lots of questions here.
You can loop the $xml->children() from the SimpleXMLElement and then check if for (string)$a->id === "1". Then use addChild to add your phone element with value 12345678 to the person element.
foreach ($xml->children() as $a) {
if ((string)$a->id === "1") {
$a->addChild("phone", "12345678");
}
}
Demo
I have an XML structure like this
<companies>
<company>
<vatno>12345678</vatno>
<name>
<founded>2013-12-31</founded>
<text>XYZ Inc</text>
</name>
<location>
<streetname>West Road</streetname>
<county>
<no>12345</no>
<text>East County</text>
<county>
</location>
</company>
</companies>
I am trying to get specific info from the elements into PHP variables.
To get "vatno" I use:
$vatno = $xmlObject->item($i)->getElementsByTagName('vatno')->item(0)->childNodes->item(0)->nodeValue;
But what if I need the county name for example?
I cannot use getElementsByTagName('text') as it would get the company name also using the element name "text".
You may be better off using SimpleXML, you can then access the various components in a more intuitive way.
The example above would be something like...
$data = <<< XML
<companies>
<company>
<vatno>12345678</vatno>
<name>
<founded>2013-12-31</founded>
<text>XYZ Inc</text>
</name>
<location>
<streetname>West Road</streetname>
<county>
<no>12345</no>
<text>East County</text>
</county>
</location>
</company>
</companies>
XML;
$xml = simplexml_load_string($data);
foreach ( $xml->company as $company ) {
echo $company->vatno.PHP_EOL;
echo $company->location->county->text.PHP_EOL;
}
So each sub element is accessed using ->.
If you wanted to stick with what you already had, you should be able to use...
$countyName = $xmlObject->item($i)->getElementsByTagName('text')->item(1)
->nodeValue;
Using item(1) will fetch the second instance of the <text> elements, so this assumes that the name will have this value as well.
It works with SimpleXML if I use
$xml = simplexml_load_string($data);
foreach ( $xml->companies->company as $company ) {
echo $company->vatno.PHP_EOL;
echo $company->location->county->text.PHP_EOL;
}
If I have the following structure in an XML File;
<?xml version="1.0" encoding="UTF-8"?>
<Document xmlns="urn:iso:std:iso:20022:tech:xsd:pain.008.001.02" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance">
<CstmrDrctDbtInitn>
<GrpHdr>
<MsgID>rBYEqfjzEU</MsgID>
<CreDtTm>2014-07-01T12:36:15</CreDtTm>
<NbOfTxs>2</NbOfTxs>
<CtrlSum>400.4</CtrlSum>
<InitgPty>
<Id>
<PrvtId>
<Othr>
<Id>IA1234567</Id>
</Othr>
</PrvtId>
</Id>
</InitgPty>
</GrpHdr>
</CstmrDrctDbtInitn>
</Document>
The above code represents one transaction between the <CstmrDrctDbtInitn> and <\CstmrDrctDbtInitn> tags. This file will be appended to include more transactions which will all start and end with a <CstmrDrctDbtInitn> and <\CstmrDrctDbtInitn> tags. I need to count the number of transactions in the file, so i basically need to count the number of <CstmrDrctDbtInitn> tags in the file. Any suggestions? Sorry if I am explaining this badly, confused!
I altered the following PHP code as suggested but no luck :(
$filename = date('Y-W').'.xml'; //2014-26.xml
//Check if a file exists
if (file_exists($filename))
{
$dom = simplexml_load_string($xml);
global $NumberTransactions;
$NumberTransactions = count($dom->CstmrDrctDbtInitn);
// call xml appendFile function
appendFile($filename);
}
else
{
// call xml createFile function
createFile($filename);
}
Assuming you mean to count the number of child nodes under GrpHdr - you could use SimpleXML:
$xml = '<?xml version="1.0" encoding="UTF-8"?>
<Document xmlns="urn:iso:std:iso:20022:tech:xsd:pain.008.001.02" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance">
<CstmrDrctDbtInitn>
<GrpHdr>
<MsgID>rBYEqfjzEU</MsgID>
<CreDtTm>2014-07-01T12:36:15</CreDtTm>
<NbOfTxs>2</NbOfTxs>
<CtrlSum>400.4</CtrlSum>
<InitgPty>
<Id>
<PrvtId>
<Othr>
<Id>IA1234567</Id>
</Othr>
</PrvtId>
</Id>
</InitgPty>
</GrpHdr>
</CstmrDrctDbtInitn>
</Document>';
$dom = simplexml_load_string($xml);
// var_dump($dom->CstmrDrctDbtInitn->GrpHdr);
echo count($dom->CstmrDrctDbtInitn->GrpHdr->children());
If you meant a variation you should be able to get a good clue of the structure by uncommenting that var_dump line and working through the object structure.
If you meant something else - give us a clue by telling us in detail what you wanted the count value to be based on your example data.
===================== UPDATED FOLLOWING CLARIFICATION BELOW=============
To count the number of CstmrDrctDbtInitn groups you can use the original example, but instead the count line would be:
echo count($dom->CstmrDrctDbtInitn);
DOMXpath::evaluate() can use Xpath to count the nodes.
// create and load
$dom= new DOMDocument();
$dom->loadXml($xml);
$xpath = new DOMXpath($dom);
// register an alias/prefix for the namespace
$xpath->registerNamespace('iso', 'urn:iso:std:iso:20022:tech:xsd:pain.008.001.02');
// get the count
var_dump($xpath->evaluate('count(//iso:CstmrDrctDbtInitn)'));
Demo: https://eval.in/169122
I am have two xml files.. I first get one and loop through it then I need to take an id from the first xml file and find it in the second one and echo out the results associated with that id. If I were to do this with SQL I would simply do this:
$query = (SELECT * FROM HotelSummary WHERE roomTypeCode = '$id') or die();
while($row=mysql_fetch_array($query)){
$name = $row['Name'];
}
echo $name;
How can I do this is in xml and php??
I recommend you to read the DOMDocument documentation.
It's quite heavy but also powerful (not always clear what happens, but the Internet shold always give you a solution)
You can simply walk through your first document, finding your Id and then find your DOMElement via an XPath.
<?php
$dom = new DOMDocument();
$dom->load('1.xml');
foreach ($dom->getElementsByTagName('article') as $node) {
// your conditions to find out the id
$id = $node->getAttribute('id');
}
$dom = new DOMDocument();
$dom->load('2.xml');
$xpath = new DOMXPath($dom);
$element = $xpath->query("//*[#id='".$id."']")->item(0);
// would echo "top_2" based on my example files
echo $element->getAttribute('name');
Based on following test files:
1.xml
<?xml version="1.0" encoding="UTF-8"?>
<articles>
<article id="foo_1">
<title>abc</title>
</article>
<article id="foo_2">
<title>def</title>
</article>
</articles>
2.xml
<?xml version="1.0" encoding="UTF-8"?>
<tests>
<test id="foo_1" name="top_1">
</test>
<test id="foo_2" name="top_2">
</test>
</tests>
Use SimpleXML to create an object representation of the file. You can then loop through the elements of the Simple XML object.
Depending on the format of the XML file:
Assuming it is:
<xml>
<roomTypeCode>
<stuff>stuff</stuff>
<name>Skunkman</name>
</roomTypeCode>
<roomTypeCode>
<stuff>other stuff</stuff>
<name>Someone Else</name>
</roomTypeCode>
</xml>
It would be something like this:
$xml = simplexml_load_file('xmlfile.xml');
for($i = 0; $i < count($xml->roomTypeCode); $i++)
{
if($xml->roomTypeCode[$i]->stuff == "stuff")
{
$name = $xml->roomTypeCode[$i]->name;
}
}
That connects to the XML file, finds how many roomTypeCode entries there are, searches for the value of "stuff" within and when it matches it correctly, you can access anything having to do with that XML entry.