Search code examples
phpxmlxpathsimplexml

xpath - search for number greater than and show parents


I'm trying to get the facility enddate higher than 20170199 and it's parents, I've tried to get the parents with parent::* but it shows the whole tree instead of the filtered view.

Given XML

<Delivery>
   <Person>
     <Name>John</Name>
     <LastName>Doe</LastName>
     <Facility>
       <TypeFacility>2</TypeFacility>
       <StartDate>20161131</StartDate>
       <EndDate>20161231</EndDate>
     </Facility>
     <Facility>
       <TypeFacility>2</TypeFacility>
       <StartDate>20161131</StartDate>
       <EndDate>20170231</EndDate>
     </Facility>
   </Person>
</Delivery>

What I've tried so far

<?php
$xmlStr = simplexml_load_file("test.xml");
$res = $xmlStr->xpath("Person/Facility[EndDate>20170199]/parent::*");
echo '<pre>';print_r($res);

Expected result

   <Person>
     <Name>John</Name>
     <LastName>Doe</LastName>
     <Facility>
       <TypeFacility>2</TypeFacility>
       <StartDate>20161131</StartDate>
       <EndDate>20170231</EndDate>
     </Facility>
   </Person>

Actual result

   <Person>
     <Name>John</Name>
     <LastName>Doe</LastName>
     <Facility>
       <TypeFacility>2</TypeFacility>
       <StartDate>20161131</StartDate>
       <EndDate>20161231</EndDate>
     </Facility>
     <Facility>
       <TypeFacility>2</TypeFacility>
       <StartDate>20161131</StartDate>
       <EndDate>20170231</EndDate>
     </Facility>
   </Person>

Solution

  • What you want is filtering out/removing all Facility nodes which have child EndDate node with the value less than 20170199 (to retain the nodes with the value greater than 20170199).

    The solution using DomDocument and DomXPath classes:

    $doc = new DOMDocument();
    //$doc->preserveWhiteSpace = false;
    $doc->load("test.xml");
    
    $person = $doc->getElementsByTagName('Person')->item(0);  // context node
    $xpath = new DOMXPath($doc);
    
    foreach ($xpath->query('Facility[EndDate <= 20170199]', $person) as $n) {
        $person->removeChild($n);
    }    
    echo $doc->saveXML($person);
    

    The output:

    <Person>
         <Name>John</Name>
         <LastName>Doe</LastName>
    
         <Facility>
           <TypeFacility>2</TypeFacility>
           <StartDate>20161131</StartDate>
           <EndDate>20170231</EndDate>
         </Facility>
       </Person>
    

    DEMO link