-1

I have xml files like this:

<?xml version="1.0" encoding="utf-8"?>
<products>
    <product ID="12345">
        <name>Sunny Beach Resort</name>
        <price currency="EUR">439.00</price>
        <URL>https://www.example.com/</URL>
        <images>
            <image>https://www.example.com/images/image.jpg</image>
        </images>
        <properties>
            <property name="country">
                <value>Spanje</value>
            </property>
            <property name="region">
                <value>Gran Canaria</value>
            </property>
            <property name="cityURL">
                <value>https://www.example.com/</value>
            </property>
            <property name="usp">
                <value>Adults only 16+</value>
                <value>Een rustpunt op een centrale plek</value>
                <value>Lichte kamers met ruimtelijke sfeer</value>
            </property>
            <property name="surrounding">
                <value>afstand tot strand circa 1 kilometer (zandstrand)</value>
                <value>afstand tot centrum: circa 1 kilometer</value>
                <value>afstand tot Barstreet circa 500 meter</value>
                <value>afstand tot luchthaven circa 30 kilometer</value>
            </property>
            <property name="serviceType">
                <value>Logies ontbijt</value>
            </property>
        </properties>
        <variations>
            <variation>
                <property name="roomType">
                    <value>2-persoonskamer luxe type voor alleengebruik</value>
                </property>
                <property name="roomOccupation">
                    <value>geschikt voor 1 persoon</value>
                </property>
            </variation>
            <variation>
                <property name="roomType">
                    <value>2-persoonskamer luxe type standaard</value>
                </property>
                <property name="roomOccupation">
                    <value>geschikt voor 2 tot 3 personen</value>
                </property>
            </variation>
        </variations>
    </product>

Where the name, url and image are very reliable values to extract in php. But when it comes to the entries they put within properties or even variations, it becomes very unreliable. Because sometimes they change the order of the data entries. Or they leave one entry out.

So the below code works today, but maybe not tomorrow, because the index number changed:

$xml = simplexml_load_file($xml_folder.$feed_file);
foreach($xml->product as $product) {
$country = $xml->product[$index]->properties->property[0]->value;
$region= $xml->product[$index]->properties->property[1]->value;
$servicetype = $xml->product[$index]->properties->property[3]->value;
$facilities = $xml->product[$index]->properties->property[13]->value;
$transporttype = $xml->product[$index]->variations->variation->property[4]->value;

// more code to put the data into html code
}

Is there any way to get the values by the name within the tag, not the index number? So something like this:

$servicetype = $xml->product[$index]->properties->property[name="serviceType"]->value;
Emiel
  • 33
  • 5

3 Answers3

2

You can iterate over the property details and see what you have. You also don't need the $xml->product in the foreach, that goes back to the parent.

$xml = new simplexmlelement($xml);
foreach($xml->product as $product) {
    foreach($product->properties->property as $property) {
        if($property['name'] == 'serviceType'){
            echo 'Service type is' . $property->value . ' for ' . $product ->name;
        }
    }
}

Demo: https://3v4l.org/bQLUa

user3783243
  • 5,368
  • 5
  • 22
  • 41
  • Wow thx, I never saw that flaw in reasoning (and working on this php file for 2 weeks now) I have replaced $xml->product[$index] with $product (makes perfect sense obviously). I think this also solves an issue I had with a foreach loop within a foreach loop. – Emiel Jan 30 '21 at 13:29
2

You could use XPath to produce the individual items, something like

$country = $product->xpath("./properties/property[@name='country']/value")[0];

Or you could build a list of all of the properties as you loop over them and create an associative array...

foreach($xml->product as $index => $product) {
    $details = [];
    foreach ( $product->properties->property as $property ){
        $details[(string)$property['name']] = (string)$property->value;
    }
    print_r($details);

which gives something like

Array
(
    [country] => Spanje
    [region] => Gran Canaria
    [cityURL] => https://www.example.com/
    [serviceType] => Logies ontbijt
)

The second method is (I think) more efficient as it does 1 pass over the data, XPath would have to be done for each element you need.

If you have multiples of some details...

foreach($xml->product as $index => $product) {
    $details = [];
    foreach ( $product->properties->property as $property ){
        $type = (string)$property['name'];
        $values = [];
        foreach ( $property->value as $value )  {
            $values[] = (string)$value;
        }

        if ( is_array($values) )   {
            $details[$type] = $values;
        }
        else    {
            $details[$type] = $values[0];
        }
    }
    print_r($details);
}

will give something like

Array
(
    [country] => Array
        (
            [0] => Spanje
        )

    [region] => Array
        (
            [0] => Gran Canaria
        )

    [cityURL] => Array
        (
            [0] => https://www.example.com/
        )

    [usp] => Array
        (
            [0] => Adults only 16+
            [1] => Een rustpunt op een centrale plek
            [2] => Lichte kamers met ruimtelijke sfeer
        )

    [surrounding] => Array
        (
            [0] => afstand tot strand circa 1 kilometer (zandstrand)
            [1] => afstand tot centrum: circa 1 kilometer
            [2] => afstand tot Barstreet circa 500 meter
            [3] => afstand tot luchthaven circa 30 kilometer
        )

    [serviceType] => Array
        (
            [0] => Logies ontbijt
        )

)
Nigel Ren
  • 56,122
  • 11
  • 43
  • 55
  • Many thanks! This is a super lightweight and elegant solution. I tested it and it works great. But some entries have multiple values. I didn't put that in my example. I updated the question. Could this solution include a array item with a comma separated list of those values for example? – Emiel Jan 30 '21 at 14:27
  • @Emiel, I've added some new code to cope with multiple data elements. – Nigel Ren Jan 30 '21 at 16:39
  • could you check your updated code for me please Nigel? It gives me the same result as the previous code. It only takes the first value within a property tag and simply ignores the others. – Emiel Jan 31 '21 at 10:53
  • @Emiel, I've updated it, I thought your data was in a different format. – Nigel Ren Jan 31 '21 at 14:49
0

I would something similar to the other answers, but using xpath:

$properties = $xml->xpath("//products//property");
foreach ($properties as $property) {
    echo  $property->attributes(). ": " . $property->value. "<br>";}

Output:

country: Spanje
region: Gran Canaria
cityURL: https://www.example.com/
serviceType: Logies ontbijt
roomType: 2-persoonskamer luxe type voor alleengebruik
roomOccupation: geschikt voor 1 persoon
roomType: 2-persoonskamer luxe type standaard
roomOccupation: geschikt voor 2 tot 3 personen
Jack Fleeting
  • 24,385
  • 6
  • 23
  • 45
  • many thx. I think I like some more control over which data to extract for my html though. I do not want to output every value they put in the xml file. – Emiel Jan 30 '21 at 17:24