PHP xpath() undefined offset 0 but element exists // LARAVEL - php

i am really having trouble getting this to work. xpath works fine in other functions in the same file. I am trying to get a specific item from the XML file, which works fine when i dd() it. But when i try to load the exact same code into a variable it prompts "undefined offset 0". I am working local with Laravel.
XML
<?xml version="1.0" encoding="UTF-8" standalone="yes"?>
<idPkg:Graphic xmlns:idPkg="http://ns.adobe.com/AdobeInDesign/idml/1.0/packaging" DOMVersion="15.1">
<Color Self="Color/u2a64f" Model="Process" Space="RGB" ColorValue="204 204 204" />
</idPkg:Graphic>
PHP
function getColor($colorID){ //$colorID = Color/u2a64f
$xml= simplexml_load_file('/Resources/Graphic.xml');
$colorNode = $xml->xpath('//Color[#Self="'.$colorID.'"]');
dd($colorNode[0]->attributes()->ColorValue);
/* outputs:
SimpleXMLElement {#316 ▼
+"0": "204 204 204"
}
*/
$fillColor = $colorNode[0]->attributes()->ColorValue; // Line of error
/* outputs:
ErrorException (E_NOTICE)
Undefined offset: 0
*/
return $fillColor;
}
EDIT:
what i just found out: when i replace the variable in xpath with the content of the variable it works.
function getColor($colorID){ //$colorID = Color/u2a64f
$xml= simplexml_load_file('/Resources/Graphic.xml');
// doesnt work
$path = '//Color[#Self="'.$colorID.'"]';
// does work
$path = '//Color[#Self="Color/u2a64f"]';
$colorNode = $xml->xpath($path);
dd($colorNode[0]->attributes()->ColorValue);
/* outputs:
SimpleXMLElement {#316 ▼
+"0": "204 204 204"
}
*/
$fillColor = $colorNode[0]->attributes()->ColorValue; // Line of error
/* outputs:
ErrorException (E_NOTICE)
Undefined offset: 0
*/
return $fillColor;
}
i just cant get my head around it... I am glad for any hints or help!

Nevermind i found the solution myself.
After checking my code again i saw that sometimes some XML nodes dont have the attribute FillColor. So i checked my param first if it is set and then proceed to xpath.

Related

I want to add x customers on Prestashop via code but with extra fields

I'm trying to add customers with a code but the PrestaShop is giving me a bug.
I'm using PHP and XML
$XMLRQString = '<?xml version="1.0" encoding="utf-8"?>'.
'<x:Winmax4GetEntitiesRQ xmlns:x="urn:Winmax4GetEntitiesRQ">'.
'</x:Winmax4GetEntitiesRQ >';
$Params=array(
'CompanyCode'=>'',
'UserLogin'=>'',
'UserPassword'=>'',
'Winmax4GetEntitiesRQXML'=> $XMLRQString
);
$return = $client->GetEntities($Params);
$XMLRSString = new SimpleXMLElement($return->GetEntitiesResult);
foreach ($XMLRSString->Entities->Entity as $entity)
{
$default_lang= Configuration::get('PS_LANG_DEFAULT');
$customer=new Customer();
$customer->email= $entity->Email;
$customer->lastname= $entity->EntityType;
$customer->firstname= [$default_lang => $entity->Name];
$customer->contribuinte= $entity->TaxPayerID;
$customer->passwd= $entity->TaxPayerID;
$customer->active = 1;
$customer->add();
}
ERROR: (1/1) ContextErrorException Warning: preg_match() expects
parameter 2 to be string, array given
in Validate.php line 172
at ValidateCore::isCustomerName(array(object(SimpleXMLElement))) in
ObjectModel.php line 1149
at ObjectModelCore->validateField('firstname',
array(object(SimpleXMLElement))) in ObjectModel.php line 981
at ObjectModelCore->validateFields() in ObjectModel.php line 284
at ObjectModelCore->getFields() in ObjectModel.php line 551
at ObjectModelCore->add(true, true) in Customer.php line 264
at CustomerCore->add() in create_clients.php line 66
When storing values from SimpleXML, if you just refer to the element itself by it's tag name - this will be an instance of SimpleXMLElement. As you want the actual content of the element, the simplest way to do this is to cast it to a string...
$customer->firstname= (string)$entity->Name;

SimpleXML-Load Child-trying to get property

I've got the following problem and I can't find my mistake probably?
I try load the following XML(Over 15k Lines) Structure:
<Config>
<SystemFiles>
<Core>
<Info>
<Network>
<Capture>
<Store>
<Mount01>
<Mount02>
</Store>
</Core>
</Config>
I need access to the Substructure of Store with each Child of it. My function looks like:
public static function get_storage_data()
{
if(file_exists('/var/www/content/data/data.xml')) :
$xml = simplexml_load_file('/var/www/content/data/data.xml');
foreach ($xml->Config->Core->Store->children() as $mount) {
echo $mount;
}
else:
write_log(sprintf("data.xml not found"));
endif;
}
Which generates the following errors (Line 8 is the foreach line):
Notice
: Trying to get property 'Store' of non-object in
/var/www/inc/storage.inc
on line
8
Fatal error
: Uncaught Error: Call to a member function children() on null in /var/www/inc/storage.inc:8 Stack trace: #0 /var/www/storage.php(30): Storage::get_storage_data() #1 {main} thrown in
/var/www/inc/storage.inc
on line
8
What did I forget here or what is my mistake? Thanks!
You don't need to include the root node name when using SimpleXML to parse XML - it's already anchored at that level.
You should just be able to change the path from
$xml->Config->Core->Store->children()
to
$xml->Core->Store->children()
Note: I'm assuming that your <Mount01> and <Mount02> nodes just contain text content, since you won't be able to echo them otherwise.
See here for a worked example: https://eval.in/1006543

Pasing vulnerabilities XML 2.0 NIST with PHP 5.6

I'm trying to parse the next xml which i attach. The problem is that i can't parse the next lines with PHP 5.6. I want to extract the attributes.
<vuln:vulnerable-configuration id="http://www.nist.gov/">
<cpe-lang:logical-test operator="OR" negate="false">
<cpe-lang:fact-ref name="cpe:/o:microsoft:windows_8:-"/>
<cpe-lang:fact-ref name="cpe:/o:microsoft:windows_8.1:-"/>
<cpe-lang:fact-ref name="cpe:/o:microsoft:windows_server_2012:-:gold"/>
<cpe-lang:fact-ref name="cpe:/o:microsoft:windows_rt:-:gold"/>
<cpe-lang:fact-ref name="cpe:/o:microsoft:windows_rt_8.1:-"/>
</cpe-lang:logical-test>
</vuln:vulnerable-configuration>
I have used the next code but i cannot capture de cpe-lang field. Also i have tried using namespaces but i cannot get the children of something inside the vuln namespace.
[$source = file_get_contents('C:/xampp/htdocs/prueba/products1.xml');
$xml = new SimpleXMLElement($source);
$entries = $xml->entry;
foreach ($entries as $entry) {
$namespace = $entry->getNameSpaces(true);
$tmp = $entry->children($namespace\['cpe-lang'\],false);
print_r($tmp)
$aux={'fact-ref'};
$config\['fact-ref'\]= (string)$entry->children('vuln', TRUE)->config->children($aux, TRUE)->logical_test->{'fact-ref'};
print_r($config);
}][1]
If i print the variable $tmp it says that the array is empty.
When i print $config it says:
Warning: main(): Node no longer exists in C:\xampp\htdocs\prueba\probando.php on line 56
Notice: Trying to get property of non-object in C:\xampp\htdocs\prueba\probando.php on line 56
Array ( [fact-ref] => )
Thanks

Using SimpleXMLElement::registerXPathNamespace - test case attached [duplicate]

This question already has an answer here:
Simplexml get attributes with a namespace
(1 answer)
Closed 7 years ago.
I have prepared a simple test case for my question - please run it on a command line with php -f test.php and you will see my problem.
I am trying to draw a rectangle area in Google maps and for that I need to extract the width, height, longitude, latitude and ZoneType from the following XML code.
Here is my test.php file:
<?php
$XML1 =<<< XML1
<?xml version="1.0" encoding="UTF-8" standalone="yes"?>
<ns13:Job_ActivateGeoFencing ns12:id="1957"
xmlns:ns5="http://www.test.com/car2x/complex_types"
xmlns:ns2="http://www.test.com/car2x/service_geofencing"
xmlns:ns13="http://www.test.com/car2x/job_request_mechanism"
xmlns:ns12="http://www.test.com/car2x/jobs">
<ns2:AreaDefinition_RectangleArea
ns2:width="668"
ns2:height="3726"
ns2:spatial_tolerance="25"
ns2:rotation_angle="0"
ns2:debouncing_time="5"
ns2:area_id="0">
<ns2:centerpoint ns5:longitude="116499160" ns5:latitude="39991920"/>
<ns2:ZoneType>GreenZone</ns2:ZoneType>
</ns2:AreaDefinition_RectangleArea>
</ns13:Job_ActivateGeoFencing>
XML1;
$xml1 = new SimpleXMLElement($XML1);
$xml1->registerXPathNamespace('ns2', 'http://www.test.com/car2x/service_geofencing');
$xml1->registerXPathNamespace('ns5', 'http://www.test.com/car2x/complex_types');
$xml1->registerXPathNamespace('ns13', 'http://www.test.com/car2x/job_request_mechanism');
$xml1->registerXPathNamespace('ns12', 'http://www.test.com/car2x/jobs');
$rects = $xml1->xpath("//ns2:AreaDefinition_RectangleArea");
var_dump($rects);
foreach ($rects as $rect) {
var_dump($rect);
#print($rect->width); # line 1
#print($rect->{'width'}); # line 2
}
?>
It does not really work as expected and only prints
array(1) {
[0]=>
object(SimpleXMLElement)#2 (0) {
}
}
object(SimpleXMLElement)#2 (0) {
}
If I uncoment the line 1, then it prints nothing.
And if I uncomment the line 2, then it prints:
object(SimpleXMLElement)#2 (0) {
}
UPDATE: With MrCode's help (thanks!) here is my code:
<?php
$XML1 =<<< XML1
... see above ...
XML1;
$xml1 = new SimpleXMLElement($XML1);
$xml1->registerXPathNamespace('ns2', 'http://www.test.com/car2x/service_geofencing');
$xml1->registerXPathNamespace('ns5', 'http://www.test.com/car2x/complex_types');
$xml1->registerXPathNamespace('ns13', 'http://www.test.com/car2x/job_request_mechanism');
$xml1->registerXPathNamespace('ns12', 'http://www.test.com/car2x/jobs');
$rects = $xml1->xpath("//ns2:AreaDefinition_RectangleArea");
foreach ($rects as $rect) {
$attributes2 = $rect->attributes('ns2', true);
$children = $rect->children('ns2', true);
$centerpoint = $children->centerpoint;
$attributes5 = $centerpoint->attributes('ns5', true);
printf("width=%d\n", $attributes2['width']);
printf("height=%d\n", $attributes2['height']);
printf("rotation_angle=%d\n", $attributes2['rotation_angle']);
printf("area_id=%d\n", $attributes2['area_id']);
printf("ZoneType=%s\n", $children->ZoneType);
printf("longitude=%d\n", $attributes5['longitude']);
printf("latitude=%d\n", $attributes5['latitude']);
}
?>
Which prints the data I needed:
# php -f test.php
width=668
height=3726
rotation_angle=0
area_id=0
ZoneType=GreenZone
longitude=116499160
latitude=39991920
Any advices (maybe to make it more robust) and improvements are welcome
The width and height are attributes not child nodes. You're accessing them as if they're child nodes $rect->width. You can access them like so:
foreach ($rects as $rect) {
var_dump($rect->attributes('http://www.test.com/car2x/service_geofencing')->width);
var_dump($rect->attributes('http://www.test.com/car2x/service_geofencing')->height);
}
The attributes() method is called on the rectangle node, passing the value of ns2 namespace.
Note: doing var_dump or print_r on SimpleXML elements doesn't always show the full internal structure. Your first var_dump appears to show empty objects, but in actual fact the objects contain the correct data.

PHP: DOMNode::appendChild to an array of Elements

I am using DOMDocument to parse an XML file. I loop through the different Elements and see if any of them is missing and I fill an array with a createElement, with the error message. At the end I'm trying to appendChild that array but I always get the same error message:
Uncaught exception 'DOMException' with message 'Wrong Document Error'
DOMNode->appendChild(Object(DOMElement))
1 {main}
thrown in /xxx/xxx.php on line 235
PHP Fatal error: Call to undefined method DOMElement::item() in /xxx/xxx.php on line 235.
the code is as follow:
$SMQuery = new DOMDocument();
$SMQuery->loadXML($params);
$response = $SMQuery->createElement('SMreply');
$errors = array();
if (!$reqtyp = $SMQuery->getElementsByTagName("tag1"))
{$errors[] = $SMQuery->createElement('error', 'tag1 Element is missing');}
if (!$reqtyp = $SMQuery->getElementsByTagName("tag2"))
{$errors[] = $SMQuery->createElement('error', 'tag2 Element is missing');}
......
if(!empty($errors))
{
foreach($errors as $error) {
$response->appendChild($error); <==== this line is causing the error !!!
}
}
Any help is much appreciated.
Cheers,
Riki.
You don't show where $response is being defined, but if it's the result of another new DOMDocument(), then that explains you error - you can't add nodes from one DOM object to another directly. It has to be imported first via ->importNode(). Only after that can you actually append it.

Categories