Search code examples
phpxmlsimplexml

next() element SimpleXML


I have an XML file:

<?xml version="1.0" encoding="UTF-8"?>
<dc>
    <category>
        <name>Personal Information</name>
        <type>
            <name>Age or Range</name>
            <item dc-numeric="1">Record 1</item>
            <item dc-numeric="2">Record 2</item>
            <item dc-numeric="3">Record 3</item>
        </type>

        <type>
            <name>Preferences</name>
            <item dc-numeric="1">Record 1</item>
            <item dc-numeric="2">Record 2</item>
            <item dc-numeric="3">Record 3</item>
        </type>         
    </category>

    <category>
        <name>Product Information</name>
        <type>
            <name>Intellectual Property</name>
            <item dc-numeric="1">Record 1</item>
            <item dc-numeric="2">Record 2</item>
            <item dc-numeric="3">Record 3</item>
        </type>
    </category>

    <category>
        <name>Business Information</name>
        <type>
            <name>Business Records</name>
            <item dc-numeric="1">Record 1</item>
            <item dc-numeric="2">Record 2</item>
            <item dc-numeric="3">Record 3</item>
        </type>
    </category>
</dc>

I am parsing the file with a PHP foreach, but having trouble with the next() function:

<?php foreach ($xml as $category) : ?>

    <?php echo $category->name; ?>
        <br /><li><?php prev($category); ?> | <?php next($category); ?></li>

<?php endforeach; ?>

I am trying to get the following output to show the previous / next categories->name in the XML:

Personal Information

  • Product Information

Product Information

  • Personal Information | Business Information

Solution

  • Xpath allows you to use expressions to fetch parts of a DOM (SimpleXML is based on DOM).

    It has concepts of context and axis. The default axis is child - the children of a node. In this case the preceding-sibling and the following-sibling are what you need. [1] is a condition for the first node in the list described by the location path before it.

    Here is a small example how to use them:

    $dc = new SimpleXMLElement($xml);
    
    foreach ($dc->category as $category) {
      $previous = $category->xpath('preceding-sibling::category[1]')[0];
      $next = $category->xpath('following-sibling::category[1]')[0];
      var_dump(
        [
          'current' => (string)$category->name,
          'previous' => $previous instanceof SimpleXMLElement 
            ? (string)$previous->name : null,
          'next' => $next instanceof SimpleXMLElement 
            ? (string)$next->name : null,
        ]
      );
    }
    

    Output:

    array(3) {
      ["current"]=>
      string(20) "Personal Information"
      ["previous"]=>
      NULL
      ["next"]=>
      string(19) "Product Information"
    }
    array(3) {
      ["current"]=>
      string(19) "Product Information"
      ["previous"]=>
      string(20) "Personal Information"
      ["next"]=>
      string(20) "Business Information"
    }
    array(3) {
      ["current"]=>
      string(20) "Business Information"
      ["previous"]=>
      string(19) "Product Information"
      ["next"]=>
      NULL
    }