1

I have following script that displays data from xml.

events.xml

<SchoolCalendar>
<CalendarEvent>
    <StartTime>07:30</StartTime>
    <Title>test Title 1</Title>
    <Location>Room 1</Location>
</CalendarEvent>
<CalendarEvent>
    <StartTime>01:10</StartTime>
    <Title>test Title 2</Title>
    <Location>Room 15</Location>
</CalendarEvent>
<CalendarEvent>
    <StartTime>03:30</StartTime>
    <Title>test Title 3</Title>
    <Location>Room 18</Location>
</CalendarEvent>
<CalendarEvent>
    <StartTime>14:30</StartTime>
    <Title>test Title 4</Title>
    <Location>Room 21</Location>
</CalendarEvent>
<CalendarEvent>
    <StartTime>14:30</StartTime>
    <Title>test Title 5</Title>
    <Location>Room 12</Location>
</CalendarEvent>
<CalendarEvent>
    <StartTime>15:30</StartTime>
    <Title>test Title 6</Title>
    <Location>Room 111</Location>
</CalendarEvent>

php code:

    $today = date("H:i");
    $lib  = simplexml_load_file("events.xml");
    $query = $lib->xpath("/SchoolCalendar/CalendarEvent[StartTime = '14:30']");

    if( $query ) {
    foreach($query as $node){
        echo "<tr>";
        echo "<td>$node->StartTime</td>";
        echo "<td>$node->Title</td>";
        echo "<td>$node->Location</td>";
        echo "</tr>";
    }
    }
    else {

    }

With the above code, it will only display the two events whose StartTime is 14:30. How can I display all the future events, tried following but nothing gets displayed.

$query = $lib->xpath("/SchoolCalendar/CalendarEvent[StartTime >= '$today']");

Any help would be much appreciated, thank you.

bickyz
  • 37
  • 2
  • 9
  • 1
    Iterate over all events and check it's `StartTime`. – u_mulder Mar 07 '19 at 15:04
  • From https://stackoverflow.com/questions/4466494/string-greater-less-and-equal-comparison-in-xmldocument, you can only do >= with numbers, so you may have to do it the long way and loop over them. – Nigel Ren Mar 07 '19 at 15:10

1 Answers1

2

Other than iterating over all events and check it's StartTime
theoretically there is a XPath solution using the >= operator with xs:time types like this:

/SchoolCalendar/CalendarEvent[xs:time(concat(StartTime, ':00')) >= xs:time('14:00:00')]

Online Demo

However, this requires XPath 2+, and with PHP you only have access to XPath 1.0 (with some XPath 2 extensions). Nonetheless, it can be done in XPath using PHP 5's DOMXPath::registerPhpFunctions.

Sample Code:

$doc = new DOMDocument;
$doc->loadXML($xml); //from string
$xpath = new DOMXPath($doc);

// Register the php: namespace (required)
$xpath->registerNamespace("php", "http://php.net/xpath");
// Register PHP functions (time_greater_thanonly)
$xpath->registerPHPFunctions("time_greater_than");
function time_greater_than($nodes)
{
  // Return true if time is greater or equal than now
  return strtotime($nodes[0]->nodeValue) >= strtotime(date("H:i"));
}
// Call custom function on the CalendarEvent nodes instead of XQuery 2+ functions
$query = $xpath->query('/SchoolCalendar/CalendarEvent[php:function("time_greater_than", StartTime)]');

if ($query) {
  foreach ($query as $node) {
    echo "<tr>";
    $values = explode("\n", trim($node->nodeValue));
    foreach ($values as $str)
      echo "<td>$str</td>";
    echo "</tr>";
  }
}

PS: To access the output of time_greater_than I simply use explode() to get the values from the text content of the current node. To dig deeper into the node in your foreach loop use xquery with the current $node as contextnode param:

$xpath->query(".//Location", $node)[0]->nodeValue

e.g.

if ($query) {
  foreach ($query as $node) {
    echo "<tr>";
    echo "<td>".$xpath->query('.//StartTime', $node)[0]->nodeValue."</td>";
    echo "<td>".$xpath->query('.//Title', $node)[0]->nodeValue."</td>";
    echo "<td>".$xpath->query('.//Location', $node)[0]->nodeValue."</td>";
    echo "</tr>";
  }
}

PPS: Never XQuery versions also have fn:current-time(). I had to use a fixed xs:time to make it work.

wp78de
  • 18,207
  • 7
  • 43
  • 71
  • thank you, same changes on my end says "This page isn’t working HTTP Error 500". Is this something on the server side ? `$query = $lib->xpath("/SchoolCalendar/CalendarEvent[xs:time(concat(StartTime, ":00")) >= xs:time('13:00:00')]` – bickyz Mar 08 '19 at 08:35
  • I am running the script in Ubuntu which has PHP version 5.5.9 which I guess has xpath 1.0 – bickyz Mar 08 '19 at 09:05
  • @bickyz I've described an alternative method that works with PHP 5 & XPath 1.0. – wp78de Mar 08 '19 at 19:11
  • Just a note that as far as I know, all versions of PHP only support XPath 1.0, because that's all that has been implemented by the [libxml](http://www.xmlsoft.org/) library it uses internall. – IMSoP Mar 09 '19 at 21:36
  • @wp78de, thank you. I have created a new php page and pasted your code, however the page displays nothing, its blank with no error. Not sure what I am missing ? I have modified the second line to `$doc->loadXML(data.xml);` – bickyz Mar 11 '19 at 11:41
  • @bickyz here is the complete sample I used: https://pastebin.com/aMfNNgtP I can successfully execute it on https://www.runphponline.com/ online. – wp78de Mar 11 '19 at 17:17
  • @wp78de, thank you very much. umm it runs on runphponline.com, same code displays nothing on my server thought. I am running PHP 5.5.9-1 in Ubuntu 14. DOM/XML API Version 20031129. – bickyz Mar 12 '19 at 09:51
  • downloaded xampp and I am getting same issue. – bickyz Mar 12 '19 at 10:30
  • @wp78de, sorry for another trouble. My xml data has "&" which is causing the php script to run. `test Title 1 & Test 2Room 1` I have tried this `$xml = htmlspecialchars($xml);` but it is not working. – bickyz Mar 13 '19 at 08:54
  • @bickyz try to clean the special characters as shown in this thread https://stackoverflow.com/a/14318580/8291949 – wp78de Mar 13 '19 at 18:21
  • @wp78de, the xmf file is generated daily from the online calendar, it is not possible to clean the xml file by editing it. – bickyz Mar 13 '19 at 19:36
  • @bickyz you are not required to clean the invalid XML manually. Read the file content, apply one of the suggested solutions from the other thread, and load the fixed XML string - or you can write it back to file if you want. – wp78de Mar 13 '19 at 19:40