ultrarun
ultrarun

Reputation: 274

PHP SimpleXML remove duplicates

I'm getting data from an xml file using php simplexml. I'm gettin the time and date of each showing of a film by splitting the TimeStamp in the Time node. Each loop brings out every date along with every time but if the showing is on more than once in the same day I want the date to be only shown once.

I thought of creating an array to then delete duplicates but that's where I'm having issues, I keep ending up creating a seperate array for each Time loop.You can see at the bottom the output I'd like. Thanks...file

<Event xmlns:i="http://www.w3.org/2001/XMLSchema-instance">
<Attributes>
    <EventAttribute>
        <Name>Event Type</Name>
        <Value>Cinema</Value>
    </EventAttribute>
    <EventAttribute>
        <Name>Venue</Name>
        <Value>Building 1</Value>
    </EventAttribute>
</Attributes>
<Description />
<Duration>0</Duration>
<FirstInstance>2019-08-02T13:30:00</FirstInstance>
<Id>220002</Id>
<ImageUrl />
<LastInstance>2019-08-08T19:00:00</LastInstance>
<Name>Spider-Man: Far From Home (12a)</Name>
<OnSaleOnWeb>true</OnSaleOnWeb>
<ThumbnailUrl />
<Times>
    <EventTime>
        <Attributes>
            <EventAttribute>
                <Name>Venue</Name>
                <Value> Building 1</Value>
            </EventAttribute>
            <EventAttribute>
                <Name>Special Performance</Name>
                <Value />
            </EventAttribute>
        </Attributes>
        <Capacity>509</Capacity>
        <EventInstanceId>376802</EventInstanceId>
        <OnSaleOnWeb>true</OnSaleOnWeb>
        <SeatsAvailable>345</SeatsAvailable>
        <SeatsLocked>164</SeatsLocked>
        <SeatsReserved>0</SeatsReserved>
        <SeatsSelected>0</SeatsSelected>
        <SeatsSold>0</SeatsSold>
        <Time>2019-08-02T13:30:00</Time>
        <WebInstanceId i:nil="true" />
    </EventTime>
    <EventTime>
        <Attributes>
            <EventAttribute>
                <Name>Venue</Name>
                <Value> Building 1</Value>
            </EventAttribute>
            <EventAttribute>
                <Name>Special Performance</Name>
                <Value />
            </EventAttribute>
        </Attributes>
        <Capacity>509</Capacity>
        <EventInstanceId>377002</EventInstanceId>
        <OnSaleOnWeb>true</OnSaleOnWeb>
        <SeatsAvailable>343</SeatsAvailable>
        <SeatsLocked>164</SeatsLocked>
        <SeatsReserved>0</SeatsReserved>
        <SeatsSelected>0</SeatsSelected>
        <SeatsSold>2</SeatsSold>
        <Time>2019-08-02T19:00:00</Time>
        <WebInstanceId i:nil="true" />
    </EventTime>
    <EventTime>
        <Attributes>
            <EventAttribute>
                <Name>Venue</Name>
                <Value> Building 1</Value>
            </EventAttribute>
            <EventAttribute>
                <Name>Special Performance</Name>
                <Value />
            </EventAttribute>
        </Attributes>
        <Capacity>509</Capacity>
        <EventInstanceId>376803</EventInstanceId>
        <OnSaleOnWeb>true</OnSaleOnWeb>
        <SeatsAvailable>345</SeatsAvailable>
        <SeatsLocked>164</SeatsLocked>
        <SeatsReserved>0</SeatsReserved>
        <SeatsSelected>0</SeatsSelected>
        <SeatsSold>0</SeatsSold>
        <Time>2019-08-03T13:30:00</Time>
        <WebInstanceId i:nil="true" />
    </EventTime>
    <EventTime>
        <Attributes>
            <EventAttribute>
                <Name>Venue</Name>
                <Value> Building 1</Value>
            </EventAttribute>
            <EventAttribute>
                <Name>Special Performance</Name>
                <Value />
            </EventAttribute>
        </Attributes>
        <Capacity>509</Capacity>
        <EventInstanceId>377003</EventInstanceId>
        <OnSaleOnWeb>true</OnSaleOnWeb>
        <SeatsAvailable>345</SeatsAvailable>
        <SeatsLocked>164</SeatsLocked>
        <SeatsReserved>0</SeatsReserved>
        <SeatsSelected>0</SeatsSelected>
        <SeatsSold>0</SeatsSold>
        <Time>2019-08-03T19:00:00</Time>
        <WebInstanceId i:nil="true" />
    </EventTime>
    <EventTime>
        <Attributes>
            <EventAttribute>
                <Name>Venue</Name>
                <Value> Building 1</Value>
            </EventAttribute>
            <EventAttribute>
                <Name>Special Performance</Name>
                <Value />
            </EventAttribute>
        </Attributes>
        <Capacity>509</Capacity>
        <EventInstanceId>376804</EventInstanceId>
        <OnSaleOnWeb>true</OnSaleOnWeb>
        <SeatsAvailable>345</SeatsAvailable>
        <SeatsLocked>164</SeatsLocked>
        <SeatsReserved>0</SeatsReserved>
        <SeatsSelected>0</SeatsSelected>
        <SeatsSold>0</SeatsSold>
        <Time>2019-08-05T13:30:00</Time>
        <WebInstanceId i:nil="true" />
    </EventTime>
    <EventTime>
        <Attributes>
            <EventAttribute>
                <Name>Venue</Name>
                <Value> Building 1</Value>
            </EventAttribute>
            <EventAttribute>
                <Name>Special Performance</Name>
                <Value />
            </EventAttribute>
        </Attributes>
        <Capacity>509</Capacity>
        <EventInstanceId>376805</EventInstanceId>
        <OnSaleOnWeb>true</OnSaleOnWeb>
        <SeatsAvailable>345</SeatsAvailable>
        <SeatsLocked>164</SeatsLocked>
        <SeatsReserved>0</SeatsReserved>
        <SeatsSelected>0</SeatsSelected>
        <SeatsSold>0</SeatsSold>
        <Time>2019-08-06T13:30:00</Time>
        <WebInstanceId i:nil="true" />
    </EventTime>
</Times>
<WebEventId i:nil="true" />
</Event>

I'm using this php to get the data from the XML file:

<?php
   $xml=simplexml_load_file("myxml.xl") or die("Error: Not Working");
    foreach($xml->Times->EventTime as $Times) {
        $filmdate =$Times->Time;
        $shortdate = date("D d M",strtotime(date($filmdate)));
        $filmtimenew = date("g.ia",strtotime(date($filmdate)));
    if( strtotime($filmdate) > strtotime('now') ) { 
        echo "<span>" . $shortdate . "</span>"; 
        echo "<a href='#'>" . $filmtimenew . "</a>";
        echo "<br>";
        }
    }
?> 

This is the output I'm getting:
Fri 02 Aug 1.30pm
Fri 02 Aug 7.00pm
Sat 03 Aug 1.30pm
Sat 03 Aug 7.00pm
Mon 05 Aug 1.30pm

But I want this without the duplicate date:
Fri 02 Aug 1.30pm 7.00pm
Sat 03 Aug 1.30pm 7.00pm
Mon 05 Aug 1.30pm

I did initially hide the duplicates with JQuery but I'd like to do it properly.

Upvotes: 0

Views: 563

Answers (2)

Parfait
Parfait

Reputation: 107587

Consider also XSLT, the declarative, special-purpose language (same type as SQL) designed to transform XML files where you can run the Muenchian Method for grouping by distinct dates using xsl:key.

PHP can run XSLT 1.0 scripts with its php-xsl library. And for your nuanced date formatting, use extended exslt and even PHP's own functions as they can be registered inside XSLT -completely new to me (posted here for future readers)!

XSLT (save as .xsl file, a special .xml file; uses two extensions for date formatting)

<xsl:stylesheet version="1.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform"
                              xmlns:date="http://exslt.org/dates-and-times"
                              xmlns:php="http://php.net/xsl">
    <xsl:output method="xml" omit-xml-declaration="yes" indent="yes"/>
    <xsl:strip-space elements="*"/>

    <xsl:key name="date_key" match="EventTime" use="date:date(Time)" />

    <xsl:template match="Event"> 
        <xsl:apply-templates select="Times"/>
    </xsl:template>

    <xsl:template match="Times">     
            <xsl:for-each select="EventTime[generate-id() =
                                       generate-id(key('date_key', date:date(Time))[1])]" >
                 <span><xsl:value-of select="concat(date:day-abbreviation(string(Time)), ' ', 
                                                    date:day-in-month(string(Time)), ' ',
                                                    date:month-abbreviation(string(Time))
                                                    )"/></span>
                 <xsl:for-each select="key('date_key', date:date(Time))" >
                     <a href="#">
                          <xsl:value-of select="php:function('date', 'g.ia', 
                                                             php:function('strtotime', 
                                                                          php:function('date', string(Time))
                                                             )
                                                )"/>
                     </a>
                     <br/>
                 </xsl:for-each> 
            </xsl:for-each>      
    </xsl:template>
</xsl:stylesheet>

PHP (no for loops or if logic)

$xml = new DOMDocument;
$xml->load('Input.xml');

$xsl = new DOMDocument;
$xsl->load('Script.xsl');

// Configure transformer
$proc = new XSLTProcessor;
$proc->registerPHPFunctions();
$proc->importStyleSheet($xsl);

// Transform XML source
$newXML = new DOMDocument;
$newXML = $proc->transformToXML($xml);

// Output to console
echo $newXML;

Output

<span>Fri 2 Aug</span><a href="#">1.30pm</a><br/><a href="#">7.00pm</a><br/>
<span>Sat 3 Aug</span><a href="#">1.30pm</a><br/><a href="#">7.00pm</a><br/>
<span>Mon 5 Aug</span><a href="#">1.30pm</a><br/>
<span>Tue 6 Aug</span><a href="#">1.30pm</a><br/>

Upvotes: 0

Nigel Ren
Nigel Ren

Reputation: 57121

What this does is build up a list of all of the dates and times and then formats the output (this can also be useful when using templates).

The array uses the date as the index and adds a new time each time one is found. The end then outputs the date followed by each element of this array....

$dates = [];
foreach($xml->Times->EventTime as $Times) {
    $filmdate =$Times->Time;
    $shortdate = date("D d M",strtotime(date((string)$filmdate)));
    $filmtimenew = date("g.ia",strtotime(date((string)$filmdate)));
    if( strtotime((string)$filmdate) > strtotime('now') ) {
        $dates [ $shortdate ][] = $filmtimenew;
    }
}

foreach ( $dates as $date =>$times ) {
    echo "<span>" . $date . "</span>";
    foreach ( $times as $time ) {
        echo "<a href='#'>" . $time . "</a>";
        echo "<br>";
    }
}

As pointed out, you will need to ensure the file loads correctly as some components are not properly formed (no namespace for i in <WebInstanceId i:nil="true" /> etc.)

Upvotes: 2

Related Questions