1

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

  • "straight bet" "price" for each "Competitor/competitorname"
  • EventURL
  • competitorname

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/

3 Answers 3

3

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);
}
Sign up to request clarification or add additional context in comments.

7 Comments

outstanding. I am mixing your first part with my other insertion code as i need to compare a little data also, but you have gotten me to where I need to be in a very elegant way. Thank you
For your sanity and future code maintainability, I strongly recommend you keep extraction separate from loading (into the DB). Put everything you need to consult for your insert logic into the intermediate $events data structure. Having an intermediate, abstracted data structure makes it much easier to test, maintain, and modularize each part individually. Imagine these scenarios: the XML feed structure changes; you want to add new feeds; the DB structure changes; you switch to a different database; etc.
One question and I will read up more on xpath, but how would I make it so that the array would instead of being [competitors] [canterbury] => 1.90 [wests] => 2.10 to be something like [competitor] [0] [competitorname]=>canterbury [price] => 1.90 [1] [competitorname]=>wests [price] => 2.10 Just to make it easier to deal with later?
This isn't an xpath issue really. Instead of the line that has $event['Competitors'][$name] = $price, do $event['Competitors'][] = array('name'=>$name, 'price'=>$price). I.E., append an array instead of assigning a value to a key.
Sorry I can't see where exists in the initial function
|
1

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);

1 Comment

Excellent that is a whole lot neater and faster than what I previously had.
0

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.

Comments

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.