[Resolved]Parsing XML for noobs?
Code:
<timetable>
<day>
<name>Monday</name>
<subject>
<starttime>8</starttime>
<endtime>9</endtime>
<name>SIT202</name>
<type>Prac</type>
<room>LT1</room>
</subject>
</day>
</timetable>
:sick: Looked at about 10 parsers, all of them are super confusing, or just leave me with this array thats about 20 dimensions and I can't figure out how to navigate it properly. Basically just trying to do a Timetable app, 5 days, many subjects to each day.
Does anyone have a really easy parser or link to a parser with some sample code? :/ I noticed PHP has SimpleXML, but it requires PHP 5. :(
Re: Parsing XML for noobs?
I think DOM XML is quite simple to use, especially with XPath to help you navigate. (DOM navigation is usually quite the horror.) If you don't know XPath, look at the W3Schools tutorial.
I'll post the simplified constructor of a class that I've used to parse a TV programme.
Here's the XML:
Code:
<schedule>
<day date="20050620">
<station id="at_orf1">
<programme start="0010" end="0400" type="film" detailid="flug_534_tod_ueber_den_wolken-USA-2001"/>
<programme start="0410" end="0600" type="series" detailid="die_simpsons-USA-1989" episode="01x02"/>
<programme start="0610" end="1100" type="show" title="Der Ganze Vormittag Mit Confetti"/>
<programme start="1110" end="1200" type="news" title="Newssplash"/>
<programme start="1210" end="1600" type="series" detailid="dawsons_creek-USA-1998" episode="01x03"/>
<programme start="1610" end="1700" type="news" title="Newssplash"/>
<programme start="1710" end="1900" type="series" detailid="malcom_mittendrinn" episode="01x03"/>
<programme start="1900" end="2000" type="series" detailid="die_simpsons-USA-1989" episode="01x11"/>
<programme start="2015" end="2400" type="film" detailid="notting_hill-UK-1999"/>
</station>
<station id="at_orf2">
<programme start="0000" end="0130" type="news" title="Zeit im Bild 3"/>
<programme start="0130" end="0500" type="show" title="Show von Gestern"/>
<programme start="0500" end="0700" type="news" title="Morgenschmarrn"/>
<programme start="0700" end="1200" type="series" title="Reich und Lang"/>
<programme start="1200" end="1400" type="news" title="Viel Zeit im Bild"/>
<programme start="1400" end="1800" type="talk" title="Die Endlose Barbara Karlich Show"/>
<programme start="1800" end="2015" type="news" title="Noch Mehr Zeit im Bild"/>
<programme start="2015" end="2400" type="docu" title="Universum" subtitle="Das Verrinnen der Zeit"/>
</station>
</day>
</schedule>
The constructor looks like this:
Code:
function XmlSchedule(&$dom, $nodeset = false)
{
if($nodeset === false) {
$this->xpathctx =& xpath_new_context($dom);
$xpr = "//programme";
$res = @$this->xpathctx->xpath_eval($xpr);
$this->nodeset = $res->nodeset;
} else {
$this->xpathctx =& $dom;
$this->nodeset = $nodeset;
}
}
The $dom parameter, provided that $nodeset is false, is a DOM XML dom cretated with domxml_open_file. This just initializes the schedule. More interesting is getAt, which looks up a programme based on time and station.
Code:
function getAt($station, $timestamp)
{
$date = $timestamp['date'];
$time = $timestamp['time'];
$stationid = $station->getId();
$xpr = "//day[number(@date) = $date]//station[@id='$stationid']".
"//programme[number(@start) <= $time and number(@end) >= $time]";
$res = @$this->xpathctx->xpath_eval($xpr);
if(isset($res->nodeset[0]) &&
array_obj_search_p($res->nodeset[0], $this->nodeset, '0') !== false)
{
return new XmlProgramme($res->nodeset[0]);
} else {
return null;
}
}
The real work is done by the XmlProgramme constructor, which turns this node into actual data.
Code:
function XmlProgramme(&$node)
{
$types = getTypes();
$this->type = $types->get($node->get_attribute('type'));
$this->extendedAttributes = array();
$known = array( 'start' => true,
'end' => true,
'type' => true,
'title' => true,
'detailid' => true
);
foreach($node->attributes() as $attr) {
if(!$known[$attr->name()]) {
$this->extendedAttributes[$attr->name()] = $attr->value();
}
}
if($this->type->hasDetail()) {
$this->detailid = $node->get_attribute('detailid');
} else {
$this->detailid = "";
}
$this->title = $node->get_attribute('title');
if(!$this->title && $this->getDetail()) {
$detail = $this->getDetail();
$this->title = $detail->getTitle();
}
$this->blurb = getNodeContent(getChildNode($node, 'blurb'));
if(!$this->blurb && $this->getDetail()) {
$detail = $this->getDetail();
$this->blurb = $detail->getSummary();
}
$stations = getStations();
$parent = $node->parent_node();
$this->station = $stations->get($parent->get_attribute('id'));
$parent = $parent->parent_node();
$startdate = $parent->get_attribute('date');
$starttime = $node->get_attribute('start');
$endtime = $node->get_attribute('end');
$startday = substr($startdate, 6, 2);
$startmonth = substr($startdate, 4, 2);
$startyear = substr($startdate, 0, 4);
$starthour = substr($starttime, 0, 2);
$startminute = substr($starttime, 2, 2);
$startdate = mktime($starthour, $startminute, 0,
$startmonth, $startday, $startyear);
$this->unixtime = $startdate;
$endhour = substr($endtime, 0, 2);
$endminute = substr($endtime, 2, 2);
$enddate = mktime($endhour, $endminute, 0,
$startmonth, $startday, $startyear);
// Seems to wrap around daybreak.
if($enddate < $startdate) {
$enddate = strtotime('+1 day', $enddate);
}
$this->time['date'] = date('Ymd', $startdate);
$this->time['time'] = date('Hi', $startdate);
$this->length = ($enddate - $startdate) / 60;
$this->importance = 1;
$this->image = createImage($this->getExtendedAttributes());
if(!$this->image && $this->getDetail()) {
$detail = $this->getDetail();
$this->image = $detail->getImage();
}
}
getNodeContent and getChildNode are simple wrapper functions.
Code:
function getNodeContent($node)
{
if(!$node) {
return '';
}
$text = '';
$chs = $node->child_nodes();
foreach($chs as $ch) {
if($ch->node_type() == XML_ELEMENT_NODE) {
$text .= getNodeContent($ch);
} else {
$text .= $ch->node_value();
}
}
return $text;
}
function getChildNode($node, $name)
{
$chs = $node->child_nodes();
foreach($chs as $ch) {
if($ch->node_name() == $name) {
return $ch;
}
}
return null;
}