maphaneuf
maphaneuf

Reputation: 77

Read and take value of XML attributes

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.

Upvotes: 0

Views: 448

Answers (3)

michi
michi

Reputation: 6625

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

Upvotes: 0

hakre
hakre

Reputation: 197832

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.

Upvotes: 1

Hearaman
Hearaman

Reputation: 8726

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/>";
    }
    ?>

Upvotes: 0

Related Questions