xpath finds nothing - PHP - 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

Related

How can I remove certain elements from XML using SimpleXML

I load the following XML data into SimpleXML like this:
<?php
$xmlString = <<<'XML'
<?xml version="1.0"?>
<response>
<item key="0">
<title>AH 2308</title>
<field_a>3.00</field_a>
<field_b>7.00</field_b>
<field_d1>35.00</field_d1>
<field_d2>40.00</field_d2>
<field_e></field_e>
<field_g2></field_g2>
<field_g>M 45x1,5</field_g>
<field_gewicht>0.13</field_gewicht>
<field_gtin>4055953012781</field_gtin>
<field_l>40.00</field_l>
<field_t></field_t>
<field_abdrueckmutter>KM 9</field_abdrueckmutter>
<field_sicherung>MB 7</field_sicherung>
<field_wellenmutter>KM 7</field_wellenmutter>
</item>
<item key="1">
<title></title>
<field_a></field_a>
<field_b></field_b>
<field_d1></field_d1>
<field_d2></field_d2>
<field_e></field_e>
<field_g2></field_g2>
<field_g></field_g>
<field_gewicht></field_gewicht>
<field_gtin></field_gtin>
<field_l></field_l>
<field_t></field_t>
<field_abdrueckmutter></field_abdrueckmutter>
<field_sicherung></field_sicherung>
<field_wellenmutter></field_wellenmutter>
</item>
</response>
XML;
$xml = simplexml_load_string($xml);
How can I achieve the following result:
<?xml version="1.0"?>
<response>
<item key="0">
<title>AH 2308</title>
<field_a>3.00</field_a>
<field_b>7.00</field_b>
<field_d1>35.00</field_d1>
<field_d2>40.00</field_d2>
<field_e></field_e>
<field_g2></field_g2>
<field_g>M 45x1,5</field_g>
<field_gewicht>0.13</field_gewicht>
<field_gtin>4055953012781</field_gtin>
<field_l>40.00</field_l>
<field_t></field_t>
<field_abdrueckmutter>KM 9</field_abdrueckmutter>
<field_sicherung>MB 7</field_sicherung>
<field_wellenmutter>KM 7</field_wellenmutter>
</item>
<item key="1"></item>
</response>
To delete all empty elements, I could use the following working code:
foreach ($xml->xpath('/child::*//*[not(*) and not(text()[normalize-space()])]') as $emptyElement) {
unset($emptyElement[0]);
}
But that's not exactly what I want.
Basically, when the <title> element is empty, I want to remove it with all its siblings and keep the parent <item> element.
What's important: I also want to keep empty element, if the <title> is not empty. See <item key="0"> for example. The elements <field_e>, <field_g2> and <field_t>will be left untouched.
Is there an easy xpath query which can achieve that? Hope anyone can help. Thanks in advance!
This xpath query is working:
foreach ($xml->xpath('//title[not(text()[normalize-space()])]/following-sibling::*') as $emptyElement) {
unset($emptyElement[0]);
}
It keeps the <title> element but I can live with that.
DOM is more flexible manipulating nodes:
$document = new DOMDocument();
$document->loadXML($xmlString);
$xpath = new DOMXpath($document);
$expression = '/response/item[not(title[normalize-space()])]';
foreach ($xpath->evaluate($expression) as $emptyItem) {
// replace children with an empty text node
$emptyItem->textContent = '';
}
echo $document->saveXML();

Add node to XML with condition

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

Display data within XML tags in PHP

The XML that's received is below. How can I get the values ('AI', '3', '20.78'...) and display them in PHP?
The values are always returned in that order but the length can vary.
<?xml version="1.0" encoding="UTF-8"?>
<Data>
<Item Type="AI" Chan="3" Value="20.78" Manual="OFF" Min="0.00" Max="100.00" Units="degC" Name="Workshop Temp" />
</Data>
Any ideas would be much appreciated!
You might find the documentation of SimpleXMLElement::attributes useful,
SimpleXMLElement::attributes β€” Identifies an element's attributes
Return Values
Returns a SimpleXMLElement object that can be iterated over to loop through the attributes on the tag.
Returns NULL if called on a SimpleXMLElement object that already represents an attribute and not a tag.
here is how you should use it:
$str = <<< XML
<?xml version="1.0" encoding="UTF-8"?>
<Data>
<Item Type="AI" Chan="3" Value="20.78" Manual="OFF" Min="0.00" Max="100.00" Units="degC" Name="Workshop Temp" />
</Data>
XML;
$xml = simplexml_load_string($str);
foreach($xml->Item[0]->attributes() as $key => $att) {
echo $att."\n";
}

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

Categories