3
<info>
    <form tableid="1">
        <town_id>
            <option value="5102">Moscow</option>
            <option value="2587">London</option>
            <option value="717">Madrid</option>
            <option value="2513">Paris</option>
            <option value="5071">Berlin</option>
        </town_id>
    </form>
</info>

I have such xml and wanna parse it throught simplexml_load_string. Function returns such object:

SimpleXMLElement Object
(
    [form] => SimpleXMLElement Object
        (
            [@attributes] => Array
                (
                    [tableid] => 1
                )

            [town_id] => SimpleXMLElement Object
                (
                    [option] => Array
                        (
                            [0] => Moscow
                            [1] => London
                            [2] => Madrid
                            [3] => Paris
                            [4] => Berlin
                        )

                )

        )

)

I don't have second attributes value from town options. How can I get them? my code:

/** @var SimpleXMLElement $xml */
$xml = simplexml_load_string($data);
if (! is_object($xml)) return FALSE;

print_r($xml);
foreach($xml as $record){
    $attr = $record->attributes();
    $table_id = (int)$attr['tableid'];
   foreach($record as $key => $value){
      //$table_data[$table_id][$key][] = $value['option'];
       print_r($value->attributes());
       print_r($value['option']->attributes());
   }
}

$value is a SimpleXMLElement object, but $value->attributes() and $value['option]->attributes() return empty array.

0

1 Answer 1

4

You can simply iterate the SimpleXMLElement objects by accessing the children with -> operator:

$xml = <<<'XML'
<info>
    <form tableid="1">
        <town_id>
            <option value="5102">Moscow</option>
            <option value="2587">London</option>
            <option value="717">Madrid</option>
            <option value="2513">Paris</option>
            <option value="5071">Berlin</option>
        </town_id>
        <town_id>
            <option value="9343">XTown</option>
        </town_id>
    </form>
</info>
XML;

$items = simplexml_load_string($xml);

foreach ($items as $form) {
    foreach ($form->town_id as $town) {
        foreach ($town->option as $option) {
            $attr = $option->attributes();
            printf("#%d - %s\n", $attr['value'], $option);
        }
    }
}

Output

#5102 - Moscow
#2587 - London
#717 - Madrid
#2513 - Paris
#5071 - Berlin
#9343 - XTown

XPath

Alternatively, use xpath method:

$options = $items->xpath('form/town_id/option');
foreach ($options as $option) {
  $attr = $option->attributes();
  printf("#%d - %s\n", $attr['value'], $option);
}

In this example I used an XPath expression relative to $items (root element, in particular). Adjust the XPath according to your needs. For example, you can fetch all options in the document with //option. Or you might even want to iterate all elements under form having option children:

$containers = $items->xpath('form/*[option]');
foreach ($containers as $c) {
  switch ($c->getName()) {
    case 'town_id':    $label = 'Towns';     break;
    case 'country_id': $label = 'Countries'; break;
    default:
      // Skipping unknown element name
      continue;
  }

  printf("\n%s\n======\n", $label);
  foreach ($c->option as $option) {
    $attr = $option->attributes();
    printf("#%d - %s\n", $attr['value'], $option);
  }
}

Sample Output

Towns
======
#5102 - Moscow
#2587 - London
#717 - Madrid
#2513 - Paris
#5071 - Berlin

Towns
======
#9343 - XTown

Countries
======
#3456 - Russia
#4566 - China
Sign up to request clarification or add additional context in comments.

4 Comments

@WebDev, have you read the example with form/*[option]? The * refers to all elements having option tag. You don't need to know the element names at all. You might even use //*[option]. In the latter case, you need to know only about option.
oh, sorry. I was confused by switch and enumeration all fields. I haven't noticed that you only set labels in switch.
one more question: how can I get options only from block form with tableid=1? Does it exist method such as $items->xpath('form[1]/*[option]'); or $items->xpath('form[2]/*[option]');
@WebDev, 'form[@tableid="1"]/*[option]'

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.