0

I am stock with this XML problem, I have a XML file that I browse to find values. Everything is working fine, I can read on all the child nodes, but I am stuck on this section. The XML portion containing photos are all the same name of the node, except for an attribute, how can I specify how to browse according to this and take the filename value of each of them

XML ... <Engine> <Fuel>Unleaded</Fuel> <Cylinders>4</Cylinders> <Induction>Normally aspirated</Induction> </Engine> <Photo order="1"> <Filename>http://usedcarpics.s3.amazonaws.com/514SPINELLITOYOTA2/b5092588_2.jpg</Filename> </Photo> <Photo order="2"> <Filename>http://usedcarpics.s3.amazonaws.com/514SPINELLITOYOTA2/b5092588_3.jpg</Filename> </Photo> <Photo order="3"> <Filename>http://usedcarpics.s3.amazonaws.com/514SPINELLITOYOTA2/b5092588_4.jpg</Filename> </Photo> <Photo order="4"> <Filename>http://usedcarpics.s3.amazonaws.com/514SPINELLITOYOTA2/b5092588_5.jpg</Filename> </Photo> <Photo order="5"> <Filename>http://usedcarpics.s3.amazonaws.com/514SPINELLITOYOTA2/b5092588_6.jpg</Filename> ... 

In my php file, I have this code that help me find the values:

$import->stock_no =(string)$item->Invoice->Vehicle->VehicleStock; $import->image1 =(string)$item->Invoice->Vehicle->Photo->attributes(order="1")->Filename; 

Of course it doesn't work, how can I browse all the photo nodes( I have 8 pictures I need to take the values from)

I want to have $import->image1 = (filename in the attibutes of pohoto 1), sames for image 2, 3, etc.

Thank you.

7
  • 1
    attributes(order="1") is not exactly valid PHP anyways... Commented Jul 8, 2013 at 18:13
  • I understand that, but how can I select photo with attribute called order="1" than order="2", ... until I reach order ="8" Commented Jul 8, 2013 at 18:19
  • For example using XPATH or just a loop over elements. Commented Jul 8, 2013 at 18:21
  • looping thru, would be something like this: $import->image1 =(string)$item->Invoice->Vehicle->Photo->Filename; $import->image2 =(string)$item->Invoice->Vehicle->Photo->Filename; $import->image3 =(string)$item->Invoice->Vehicle->Photo->Filename; $import->image4 =(string)$item->Invoice->Vehicle->Photo->Filename; Commented Jul 8, 2013 at 18:24
  • No, a loop is either foreach, while, or for. Commented Jul 8, 2013 at 18:27

3 Answers 3

1

What you try to achieve is (first of all) possible by using an xpath query. You want to access a child-node based on an attribute value. The better reference questions in SimpleXML are:

It's also since some days when the suggestion was given to extend form SimpleXMLElement to provide a utility function to actually do that with an easy interface:

However your case is a little different because of the syntax you suggest:

$xml = simplexml_load_string($buffer, 'MySimpleXMLElement'); echo $xml->Vehicle->Photo->attribute("order", "1")->Filename; // prints "http://usedcarpics.s3.amazonaws.com/514SPINELLITOYOTA2/b5092588_2.jpg" 

Instead of using an ordinary SimpleXMLElement this example uses an extended one named (exemplary) MySimpleXMLElement. It runs an XPath query inside based on the input parameters and based on the parent element it operates on (here being a Photo element):

/** * Class MySimpleXMLElement * * Example of how to magically access named child-nodes based * on an attribute value of theirs. */ class MySimpleXMLElement extends SimpleXMLElement { public function attribute($name, $value) { $nodes = $this->xpath( sprintf('../%s[@%s = "%s"]', $this->getName(), $name, $value) ); return $nodes ? $nodes[0] : NULL; } } 

This new MySimpleXMLElement::attribute() method (sorry attributes() was already in use) is then available on every node. So have fun.

Naturally you can also write it this way:

$xml = simplexml_load_string($buffer); echo $xml->Vehicle->xpath('Photo[@order="1"]')[0]->Filename; // prints "http://usedcarpics.s3.amazonaws.com/514SPINELLITOYOTA2/b5092588_2.jpg" 

the extended SimpleXMLElement is mainly for convenience reasons. And it's probably more easy to debug in case you're not fluent with Xpath yet.

Last time I extended SimpleXMLElement on Stackoverflow was in the said answer to the "simplexml_load_file - redundant element with empty value is converted to new SimpleXMLElement Object" question.

Sign up to request clarification or add additional context in comments.

5 Comments

I get an error if I write it like you did. unexpected '[', expecting ',' or ';'
I assume for the last example? If so, that is because you're probably using PHP 5.3 or 5.2 which are end of live. Upgrade to PHP 5.4 minimum or change to older array-access with the help of an additional function or variable. $nodes = $xml->Vehicle->xpath('Photo[@order="1"]'); echo $nodes[0]->Filename; - Also take care that I use the shortened example XML, so you paths to the elements are likely to be different then I have in the answer
Here is an online demo: eval.in/36953 - It also shows at the very end that - as the images are already ordered - you can also access them by their zero-based index with square brackets.
I have my code working, I used: echo $xml->Vehicle->Photo[0]->Filename, "\n"; and I get the image just like I wanted. Thank you very much.
Yes, that exactly what I had in there as the last example. Sometimes it's easier than you first think.
0

Try this

 <?php $xml = '<Engine> <Fuel>Unleaded</Fuel> <Cylinders>4</Cylinders> <Induction>Normally aspirated</Induction> </Engine> <Photo order="1"> <Filename>http://usedcarpics.s3.amazonaws.com/514SPINELLITOYOTA2/b5092588_2.jpg</Filename> </Photo> <Photo order="2"> <Filename>http://usedcarpics.s3.amazonaws.com/514SPINELLITOYOTA2/b5092588_3.jpg</Filename> </Photo>'; $xml="<Wraper>".$xml."</Wraper>"; $parse=new SimpleXMLElement($xml); echo "Engine Fuel:".$parse->Engine->Fuel; echo "<br/>Engine Cylinders:".$parse->Engine->Cylinders; echo "Photos<br/>"; foreach ($parse->Photo as $photo) { echo "<br/>Photo Order: ".$photo->attributes(); echo "<br/>Photo URL: ".$photo->Filename; echo "<hr/>"; } ?> 

Comments

0

sweet and simple with xpath:

$xml = simplexml_load_string($x); // assume XML in $x $photos = $xml->xpath("//Photo"); // select all Photo nodes and their children in an array foreach ($photos as $photo) echo "order: $photo[order], file: $photo->Filename<br />"; // simple output 

see it working: http://3v4l.org/SJmEg

4 Comments

@maphaneuf click the blue eval button below the code, then see the generated output below that.
almost, I had to change project, will return to this this afternoon.
I actually have a working solution, I tryed this morning and It works. Here is what I have working, solution provided by hakre
eval.in/36953 I just used the echo $xml->Vehicle->Photo[0]->Filename, "\n"; and it works because my iamge are all already in the right order. THank you to all

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.