Access and update attribute value in XML using XPath and PHP - php

this is an extension to my previous post today which can be found here: Click Here
Now I want to access another attribute based upon the id attribute and change that as well. Here is my modified xml file:
<?xml version="1.0" encoding="ISO-8859-1"?>
<document>
<item id="a12sd">
<name>James</name>
<age years="25"/>
<pdf>0023.pdf</pdf>
</item>
<item id="rdf23">
<name>Alex</name>
<age years="35"/>
<pdf>0178.pdf</pdf>
</item>
<item id="2we34">
<name>Tom</name>
<age years="25"/>
<pdf>0886.pdf</pdf>
</item>
<item id="123de">
<name>Robby</name>
<age years="28"/>
<pdf>1239.pdf</pdf>
</item>
</document>
I have been able to update the tags using this code:
$id = "a12sd";
$xml = simplexml_load_file('items.xml');
$itemsList = $xml->xpath('/document/item[#id = "a12sd"]');
$itemsList[0]->name = "Arnold";
$xml->asXml("items.xml");
Now I need to access the attribute age for the id="a12sd" and update the age to say: 26
Any idea how I can reach that attribute for given id and change that value.
Note: before changing the value the user knows only the "id" value, so based upon id value I want to change years attribute for that particular id.
Thanks

$itemsList[0]->age->attributes()->years = 26;

Related

xpath finds nothing - PHP

Introduction
I have some codes in SQL. I go code by code in while loop in php and search these codes in XML feed.
Programm code
I have the following programm code
$x_search = $xml->xpath("//Item[#Sort='$sort']");
if(!$x_search){
$x_Id = $x_search[0]->attributes()->Id;
echo $sort." - ".$x_Id."<BR />";
}
Problem
It is possible, that some code is not in SQL. So I get this error message:
Undefined offset: 0 in
How to do something like if you find it in XML, $x_Id = $x_search[0]->attributes()->Id;?
I have tried already:
$x_search = $xml->xpath("//*[#Sort='$sort']");
if(!empty($x_search)){
if(isset($x_search)){
Example XML:
<?xml version="1.0" encoding="utf-8"?>
<Root>
<Item Id="12860" IdP="-2147483648" Sort="0001KC" Name="Computers">
<StoItem />
</Item>
</Root>
Examples for $sort:
00004M
12860
12859
12859
12861
12861
12862
12862
12863
12863
12864
Thank you
SimpleXMLElement::xpath() always returns an array of SimpleXMLElement objects. The array is empty, if nothing is matched. The result can equal false, if the expression is invalid (programming error). So if (!empty($x_search)) ... or if ($x_search) ... can be used as condition to check the result. false is an empty value and an empty array equals false. Both conditions will only be true if the result from the expression is an array with at least a single element.
$xmlString = <<<'XML'
<?xml version="1.0" encoding="utf-8"?>
<Root>
<Item Id="12860" IdP="-2147483648" Sort="0001KC" Name="Computers">
<StoItem />
</Item>
</Root>
XML;
$xml = new SimpleXmlElement($xmlString);
$sort = '0001KC';
$x_search = $xml->xpath("//Item[#Sort='$sort']");
if (!empty($x_search)) {
$x_Id = $x_search[0]->attributes()->Id;
echo $sort." - ".$x_Id."<BR />";
}
Output: https://eval.in/406640
0001KC - 12860<BR />
Most of your example values for $sort look like Id attribute values. The second one, is the Id attribute value in the example XML.
If you want to match the Id attribute, the Xpath expression would be:
//Item[#Id='$sort']
It is even possible to match both attributes:
//Item[#Id='$sort' or #Sort='$sort']
This is an example of the XML. A I wrote it is possible, that some code is not in SQL. So that's why I need to solve this problem. Something like write me an echo only if you find this sort in XML.
<?xml version="1.0" encoding="utf-8"?>
<Root>
<Item Id="12860" IdP="-2147483648" Sort="0001KC" Name="Computers">
<StoItem />
</Item>
</Root>
The begin of the list of codes that enter invariable $sort
00004M
12860
12859
12859
12861
12861
12862
12862
12863
12863
12864

Error adding new item

All good day. When using crxml repository, not correctly generated xml document. And that's what happens when you add a new element into the document. Course of action:
To begin with I create document
$this->genXml->Item['Type'] = 'view';
$this->genXml->Item->{'http://'.$this->siteUrll.'|Name'} = 'Last View';
$this->genXml->Item->LastView->View->Time = $app['Time'];
$this->genXml->Item->LastView->View->Action = $app['Action'];
$this->genXml->Item->LastView->View->IP = $app['IP'];
return $this->genXml->xml();
and I get this kind of xml file
<?xml version="1.0" encoding="UTF-8"?>
<Item Type="view">
<Name xmlns="http://sitename.com">Last View</Name>
<LastView>
<View>
<Time>11:45:12</Time>
<Action>Click</Action>
<IP>192.168.1.1</IP>
</View>
</LastView>
</Item>
further to the finished result add new values
$GetFile = <<<EOB
<?xml version="1.0" encoding="UTF-8"?>
<Item Type="view">
<Name xmlns="http://sitename.com">Last View</Name>
<LastView>
<View>
<Time>11:45:12</Time>
<Action>Click</Action>
<IP>192.168.1.1</IP>
</View>
</LastView>
</Item>
EOB;
$this->genXml->loadXML($GetFile);
$this->genXml->Item->LastView->View[2]->Time = $app['Time'];
$this->genXml->Item->LastView->View[2]->Action = $app['Action'];
$this->genXml->Item->LastView->View[2]->IP = $app['IP'];
echo($this->genXml->xml());
and get the faulty code xml
<?xml version="1.0" encoding="UTF-8"?>
<Item Type="view">
<Name xmlns="http://sitename.com">Last View</Name>
<LastView>
<View>
<Time>11:45:12</Time>
<Action>Click</Action>
<IP>192.168.1.1</IP>
</View>
<View/><View><Time>11:45:12</Time><Action>Click</Action> <IP>192.168.1.1</IP></View></LastView>
</Item>
namely where the tag is
<View/>
Help solve a problem with the output. Maybe I am doing something wrong? (sorry for my English, I know im not as good as I would like)
Just give the link to the repository and a description of the problem.
It is somehow hilarious as it is a typical problem of Informatics. We like to start counting from 0. You created a first view with the ID 0 (implicit). If you now add a new view with the ID 2, it misses the ID 1 and simply inserts an empty view. The result is thereby syntactically correct.
You just have to change the index of the added view to 1 to prevent this.

Getting information from more than one large XML file

I am trying to get information from external large xml files; from file 1 (vehicleList.xml) and file 2 (CheckVehicles.xml) into a PHP file. All values in XML file 2 are in XML file 1. I would like to display only values in file 1 that are in XML file 2.
My foreach loop code can bring results for up to 130 items (that is if I reduce the items in XML file 2 to 130 items/nodes). However if I remove the if statement, I am able to get all the 3340 items/vehicles from XML file 1.
Where am I going wrong? I tried arrays but failed.
Here is my code:
//XML FILE 1 with 1300 items
$myXML = new SimpleXMLElement('CheckVehicles.xml', NULL, TRUE);//
foreach($myXML->root->item as $item){
$listArrayNew[(int)$item->value] = (int)$item->value;
}
//XML FILE 2 with 3340 vehicles
$parser = new SimpleXMLElement('vehicleList.xml', NULL, TRUE);
foreach ($parser->GetVehiclesListResponse->GetVehiclesListResult->Vehicle as $Vehicle) {
if($listArrayNew[(int)$Vehicle->ID] == (int)$Vehicle->ID){
$vehicle = $Vehicle->Description;
$regNumber = $Vehicle->RegistrationNumber;
$siteID = $Vehicle->SiteID;
$row .= "<tr>
<td>".$vehicle."</td>
<td>".$regNumber."</td>
<td>".$siteId."</td>
</tr>";
}
}
Here are the XML files:
XML file 1: vehicleList.xml
<?xml version="1.0" encoding="utf-8"?>
<soap:Envelope>
<GetVehiclesListResponse>
<GetVehiclesListResult>
<Vehicle>
<ID>153</ID>
<SiteID>11</SiteID>
<GroupID>3</GroupID>
<Description>A.O Basid KAR 459 E</Description>
<RegistrationNumber>KAR 459 E</RegistrationNumber>
</Vehicle>
..............................
<Vehicle>
<ID>3340</ID>
<SiteID>25</SiteID>
<GroupID>4</GroupID>
<Description>UAR 712B White Nissan Tiida (Deus Mubangizi)</Description>
<RegistrationNumber>UAR 712B</RegistrationNumber>
</Vehicle>
</GetVehiclesListResult>
</GetVehiclesListResponse>
</soap:Envelope>
XML file 2: CheckVehicles.xml
<?xml version="1.0" encoding="utf-8"?>
<Result>
<root>
<item>
<index>0</index>
<value>153</value>
</item>
...................
<item>
<index>1300</index>
<value>128</value>
</item>
</root>
</Result>
I don't know where you go wrong in your case. However if you want to select elements from the second file based on a criteria (e.g. an ID / unique Number) from the first file I suggest you make use of xpath in your case:
Obtain the numbers from the first file that are the criteria (e.g. /*/root/item/value)
Select all elements from the second file that match the criteria (e.g. ID in /*/GetVehiclesListResponse/GetVehiclesListResult/Vehicle).
The later point can best be achieved by using the technique outlined in Is there anything for XPATH like SQL “IN”? which is creating a comma separated list of the numbers to select and then compare this against each elements number.
Example:
Consider there 2 500 out of 10 000 elements in a first file and in a second file there are 10 000 elements. Each element can be uniquely identified by it's ID.
The first file has this layout:
<?xml version="1.0"?>
<root>
<item>
<index>0</index>
<id>604</id>
</item>
<item>
<index>1</index>
<id>2753</id>
</item>
...
</root>
And the second file has this layout.
<?xml version="1.0"?>
<list>
<item>
<id>1</id>
<some>Number: 33</some>
</item>
<item>
<id>2</id>
<some>Number: 35</some>
</item>
...
</list>
The xpath query to get all IDs from the first file therefore is:
//item/id
And the query for the second file can be expressed with SimpleXML in PHP as:
$ids = implode(',', $file1->xpath('//item/id'));
$query = '//item[contains(",' . $ids . ',", concat(",", id, ","))]';
You can find example code of that example here: http://eval.in/6370

How to make child xml node with while loop using php

$xml = new DOMDocument();
$root=$xml->createElement("ROOT");
$xml->appendChild($root);
$data=$xml->createElement("DATA");
while($row=db_fetch_object($result))
{
$data=$xml->createElement("ITEM");
$item->setAttribute("COMPANY",$row->field_windmill_fabrikant_value);
$item->setAttribute("HEIGHT",$row->field_windmill_ashoogte_value);
$item->setAttribute("POWER",$row->field_windmill_vermogen_value);
$item->setAttribute("LOCATION",$row->field_windmill_provincie_value);
$item->setAttribute("START_YEAR",$row->field_windmill_startjaar_value);
$data->appendChild($item);
}
$root->appendChild($data);
echo $xml->saveXML();
Here I want to append ITEM as a child node to data but ITEM is getting appended to item and not to data. I'm using PHP.
Can anyone help in it.
Thanks.
Just replace
$data=$xml->createElement("ITEM");
with
$item=$xml->createElement("ITEM");
result of this will be
<?xml version="1.0"?>
<ROOT>
<DATA>
<ITEM COMPANY="COMPANY0" HEIGHT="HEIGHT0" POWER="POWER0" LOCATION="LOCATION0" START_YEAR="START_YEAR0"/>
<ITEM COMPANY="COMPANY1" HEIGHT="HEIGHT1" POWER="POWER1" LOCATION="LOCATION1" START_YEAR="START_YEAR1"/>
<ITEM COMPANY="COMPANY2" HEIGHT="HEIGHT2" POWER="POWER2" LOCATION="LOCATION2" START_YEAR="START_YEAR2"/>
</DATA>
</ROOT>

Help! How to add Child to specify Node using PHP simpleXML?

my xml structure is:
<users>
<user id="126">
<name>老黄牛三</name>
<watchHistory>
<whMonthRecords month="2010-10">
<whDateList month="2010-10">
<date>01</date>
<date>02</date>
<date>05</date>
<date>08</date>
<date>21</date>
</whDateList>
<whDateRecords date="2010-10-01">
<item itemID="1">飞越疯人院.老黄牛三.2010-10-01</item>
<item itemID="4">回到未.老黄牛三.2010-10-01来</item>
<item itemID="5">天天看的哦啊你.2010-10-01来</item>
</whDateRecords>
<whDateRecords date="2010-10-05">
<item itemID="1">飞越疯人院.老黄牛三.2010-10-05</item>
<item itemID="4">回到未来.老黄牛三.2010-10-05</item>
</whDateRecords>
</whMonthRecords>
<whMonthRecords month="2010-11">
........
</whMonthRecords>
<watchHistory>
</user>
</users>
now, how can I add child :
<whDateRecords date="2010-10-06">
<item itemID="45">飞越疯人院.老黄牛三.2010-10-05</item>
<item itemID="432">回到未来.老黄牛三.2010-10-05</item>
</whDateRecords>
to the node:<whMonthRecords month="2010-10">
Thank you very much!
First, look for the parent of the node you want to add, say you want to add it to the node with month 2010-10, use this xpath:
$xpath = '//whMonthRecords[#month="2010-10"]';
$nodes = $sxml->xpath($xpath); //sxml is the xml object!
$parent = $nodes[0];
Now that you have the parent, you can add the node using addChild method.

Categories