Dannymh
Dannymh

Reputation: 149

Parsing complex XML to PHP and database

I have the following feed which I wish to parse and grab certain data from http://xmlfeeds.centrebet.com/xmlRugbyLeaguefeed.xml

Whilst I was able to do this in past using a class to pull the XML into an array. I am suffering a few complications with it now, and there have been changes almost weekly that have made it hard to automate the grabbing as I was basing it on specific keywords.

What I want to grab from the XML is only the master events that have the attribute of TopLevelName="NRL Round 18" (this will obviously change each week to round 19, 20 etc)

I then only need to get the following for each of the events under that masterevent

I ave scrapped my code as it was overly complex but can paste it if you like, I was using this XML parser http://www.bin-co.com/php/scripts/xml2array/

Upvotes: 1

Views: 1361

Answers (3)

Francis Avila
Francis Avila

Reputation: 31621

You can do this very easy with SimpleXML, XPath, and for-each loops.

There are only a few things to keep in mind with SimpleXML objects:

  • Each element becomes a SimpleXMLElement
  • Access the attributes of a SimpleXMLElement with array-notation (e.g., Element['attributeName'])
  • Access child elements of a certain name with object-notation (e.g., Element->ChildElements or Element->{Child-Element-With-Strange-Name})
  • Always cast to a string to get the text value (e.g. (string) Element or (string) Element['attribute'])
  • For fancier queries, use the xpath method.
  • To access namespaced elements, use the children method's first argument.

In general, whenever you have data-structured (vs document-structured) XML of a moderate size, the path of least resistance is SimpleXML. If you have a very large document, use a combination of XMLReader to break the document up into chunks, and XMLReader::expand() to process those chunks using DOMDocument or SimpleXML.

The following function will extract the data you want into a structured array:

function extractDataFromFeed($feeduri) {
    $events = array();

    $sxe = simplexml_load_file($feeduri);
    $targetMasterEvents = $sxe->xpath('/EventData/MasterEvents[starts-with(./@TopLevelName, "NRL Round ")]');
    foreach ($targetMasterEvents as $targetMasterEvent) {
        foreach ($targetMasterEvent->Event as $targetEvent) {
            $event = array(
                'EventUrl' => (string) $targetEvent['EventURL'],
                'Competitors' => array(), // CompetitorName => StraightBetPrice,
                                          // (assumes 1 price per competitorname)
            );

            foreach ($targetEvent->Competitors as $targetCompetitor) {
                $targetBets = $targetCompetitor->xpath('BetType[@BetTypeName="Straight Bet"]');

                foreach ($targetBets as $targetBet) {
                    $event['Competitors'][(string) $targetCompetitor['CompetitorName']]
                        = (string) $targetBet['Price'];
                }
            }
        }

        $events[] = $event;
    }
    return $events;
}


$FEED = 'http://xmlfeeds.centrebet.com/xmlRugbyLeaguefeed.xml';
$events = extractDataFromFeed($FEED);

var_export($events);

From here it is a simple matter to insert this data into a database (code below is untested):

function insertEvents($eventname, $events, PDO $pdo) {
    // Set exception mode (if not set already)
    $old_ERRMODE = $pdo->getAttribute(PDO::ATTR_ERRMODE);
    $pdo->setAttribute(PDO::ATTR_ERRMODE, PDO::ERRMODE_EXCEPTION);

    // create prepared statements
    $insertEvent = $pdo->prepare('INSERT INTO events (EventName, EventURL) VALUES (?,?)');
    $insertBet = $pdo->prepare('INSERT INTO bets (event_id, CompetitorName, Price) VALUES (?,?,?)');

    // bind statement parameters
    $insertEvent->bindValue(1, $eventName, PDO::PARAM_STR);
    $insertEvent->bindParam(2, $eventURL, PDO::PARAM_STR);
    $insertBet->bindParam(1, $event_id, PDO::PARAM_INT);
    $insertBet->bindParam(2, $competitorName, PDO::PARAM_STR);
    $insertBet->bindParam(3, $price);

    // loop through event array, executing inserts
    foreach($events as $event) {
        $eventUrl = $event['EventURL'];
        $insertEvent->execute();
        $event_id = $pdo->lastInsertId();
        foreach($event['Competitors'] as $competitorName => $price) {
            $insertBet->execute();
        }
    }

    // restore ERRMODE setting (won't be restored if exception is raised!)
    $pdo->setAttribute(PDO::ATTR_ERRMODE, $old_ERRMODE);
}

Upvotes: 3

John C
John C

Reputation: 8415

As @MDrollette suggested, SimpleXML parser is probably the best way. Combined with XPath to do some searching, you should be able to build a quick, flexible parser to get the data you need.

This is a quick example that will grab the data you are after as a multi-dimensional array. You'll need to revise it to best match what will work for your application.

$xml = new SimpleXMLElement($string);

// Find all the MasterEvents we are looking for
$masterevents = $xml->xpath('//MasterEvents[@TopLevelName="NRL Round 18"]');

$me_array = array();

foreach ($masterevents as $masterevent) {
    $event_array = array();
    // Loop through the Events
    foreach($masterevent->Event as $event) {
        $event_array['url'] = (string)$event['EventURL'];
        // Loop through the competitors / betting
        foreach($event->Competitor as $competitor) {
            $competitor_array = array();
            $competitor_array['name'] = (string)$competitor['CompetitorName'];
            $competitor_array['bettype'] = (string)$competitor->BetType[0]['BetTypeName'];
            $competitor_array['betprice'] = (string)$competitor->BetType[0]['Price'];
            $event_array['competitors'][] = $competitor_array;
        }
    }
    $me_array[] = $event_array;
}

// Dump out the results for as a demo
var_dump($me_array);

Upvotes: 1

MDrollette
MDrollette

Reputation: 6927

You can use the standard SimpleXML parser. There are plenty of example here http://php.net/manual/en/simplexml.examples-basic.php

This is much more flexible than trying to use arrays.

Upvotes: 0

Related Questions