Google

Friday, October 20, 2006

Rants of a Snake Charmer - III


XmlParser


This is a minimal XML parser that does what it is supposed to. The implementation is based on regular expressions. It is adapted from REX by Robert D. Camron.


Background


When Google Maps used to send the data objects needed by their AJAX framework in plain XML, I needed an XML parser to get location/directions data from the Google Maps server. In my earlier blog, I mentioned that PyS60 can seamlessly take modules from the desktop Python. But there are certain exceptions to that and the XML framework in Python happens to be one of them. I tried improting Python XML framework to PyS60 without any success and hence needed to find my own solution. As mentioned earlier, this XML Parser implementation is based on REX. I found REX when I was searching for the best approach to my solution. Robert Cameron has a set of regular expressions that can be used - very easily and effectively - to parse XML content. The following copyright notice and the license appear in the code.

# Robert D. Cameron "REX: XML Shallow Parsing with Regular Expressions",
# Technical Report TR 1998-17, School of Computing Science, Simon Fraser
# University, November, 1998.
# Copyright (c) 1998, Robert D. Cameron.
# The following code may be freely used and distributed provided that
# this copyright and citation notice remains intact and that modifications
# or additions are clearly identified.

The regular expressions for parsing the XML file are not modified in any way. Only the language in which the RE are implemented is changed to Python. The RE support is included in the PyS60 package.

The technical report can be found here.

Usage

XmlParser.py: This module can be used to

  • Parse an XML file
  • Parse an XML string

XMLNode Class


addProperty(property, value)

Adds a property and its value to the node. The property is added as an entry to the "properties" dictionary

addChild(tag, node)

Adds a child to the current node that can be accessed by the "tag". If there is more than one child to the current node by the same "tag", the children are added as an array in the order each child is encountered

setContent

Sets content of the current node. If the current node already contains content, then this content is appended to it

properties

A dictionary containing properties and their values of the current node

childnodes

A dictionary containing arrays containing children indexed by their tags

content

The actual content inside the tags

XMLParser Class


parseXMLFile(file)

Parses an XML file

parseXML(xmlBuffer)

Parses XML buffer passed as a string

getElementsByTagName(tag)

Traverses the minimal DOM tree PREorder and returns the array containing node(s) having "tag" name

root

Holds the root of the DOM tree

The user can decide to disregard some tags (not include them in the DOM tree) by adding them to the following array:



# Unsupported tags (HTML formatting tags for displaying info)
unSupportedTags = ['b', 'i', 'u']

Example Usage

Example XML file:

<?xml version="1.0"?>
<page>
<title>mumbai india</title>
<query>mumbai india</query>
<request>
<url>http://maps.google.com/maps?q=mumbai+india&amp;num=10</url>
<query>mumbai india</query>
</request>
<center lat="18.959999" lng="72.819999"/>
<span lat="0.089989" lng="0.095151"/>
<overlay panelStyle="/maps?file=gp&amp;hl=en">
<location infoStyle="/maps?file=gi&amp;hl=en" id="A">
<point lat="18.959999" lng="72.819999"/>
<icon class="noicon"/>
<info>
<address>
<line>Bombay</line>
<line>India</line>
</address>
</info>
</location>
</overlay>
</page>

To find out the "lat" and "lng" properties of "point" element:

...
locxml = ... Above XML ...
parser = XMLParser()
parser.parseXML(locxml)
pointNode = parser.getElementsByTagName('point')
if pointNode is None:
appuifw.note(u'Address not found', 'error')
else:
addressNode = parser.getElementsByTagName('address')
lines = []
if addressNode is not None:
lineNodes = addressNode.childnodes['line']
for node in lineNodes:
lines.append(node.content)
lat = float(pointNode.properties['lat'])
lng = float(pointNode.properties['lng'])
...

Summary

This little module is an evidence that with minimal effort, complex things can be done with the help of PyS60 on your handset.

Google

Tuesday, October 17, 2006

Rants of a Snake Charmer - II


Traffic App


Background


This is a small application that displays the realtime traffic data to the user. I was inspired by a nifty little sample program in the BREW SDK that allowed the San Diego county traffic data available on CalTrans website to be viewed in a specialized client on the handset. Of course, the BREW SDK being as complicated as it is, this solution is easier on the eyes.


Things You Need


The PyS60 is an essential subset of Python. All the must-have features of Python are packaged with it. What this also means is most platform independent features of Python can be simply added to PyS60. The task of porting the programs that rely on these features becomes quite straightforward. For the Traffic App, you will need the following modules from your local Python installation:

  1. formatter.py
  2. htmlentitydefs.py
  3. HTMLLIB.PY
  4. markupbase.py
  5. SGMLLIB.PY

Once you have copied these modules to the libs folder (or resource folder on S60 3rd ed.), we are ready to put the Traffic App in place.

Network Data

The data needed for this particular application is requested from the folowing URL:

This data is the following format:

<HTML>
<HEAD>....
</HEAD>
<BODY>...
<TABLE><CAPTION>[Highway Name]--[Date]--[Time]</CAPTION>
<TR><TD class=head>LOCATION</TD><TD class=head>SPEED<BR></TD></TR>
<TR><TD>[Exit 1]</TD><TD class=green>58 mph</TD></TR>
<TR><TD>[Exit 2]</TD><TD class=green>59 mph</TD></TR>
<TR><TD>[Exit 3]</TD><TD class=yellow>37 mph</TD></TR>
<TR><TD>[Exit 4]</TD><TD class=red>18 mph</TD></TR>
<TR><TD>[Exit 5]</TD><TD class=menuitem>no data</TD></TR><TR>
</TABLE>
</BODY>
</HTML>
What we need for a bare minimum Traffic App is an HTTP client and a parser that understands the predefined format mentioned above. Since Python and thus PyS60 readily provide the HTTP parser and HTML parser framework, all we need is a simple UI, a traffic parser, and we are done.

Code

The following files are in the codebase:

  • traffic.py (Module to parse the response from the traffic data server)
  • trafficapp.py (The application)
  • speeds.mbm (Icons)

The code can be found here. The snapshots are on top of the blog.

Summary

I hope you enjoyed this little application. I would recommend that you take the following points home:

  • Talking in HTTP with PyS60
  • HTML parsing with PyS60
  • Using icons in a ListBox
Google

Monday, October 16, 2006

Rants of a Snake Charmer - I


I have been fiddling a lot with Python ever since Python for Series 60 was launched. Python on a phone gives power to the end-user (who also wears the shoes usually worn by a developer) to make the phone do fantastic things.


Python


Python is scripting language in the league of languages such as Perl. Perl is a universal measure for one's 'geekiness'. Although I would like to be remembered as a geek, I cannot help but prefer Python for its elegance (as compared to Perl) and as for Perl as a 'geekiness' measure, I cannot call myself a geek! :(


Python for Series 60 (Or PyS60)


Good folks at Nokia Research Center started this project in Dec 2004 and I was right on their tail. Armed with only a Nokia 3650 - a very old Series 60 1.2 product, I started learning the Python language; and became - the Snake Charmer!


The platform has evolved considerably in the past year and a half. Although this platform is good for RAD type prototype development, PyS60 community has produced highly functional and some complex programs.


In this series, I will publish my applications - small and large. These include:



  • Real-time Traffic Monitor for San Diego, CA freeways

  • XML Parser

  • Virtual Earth Maps API

I hope you will enjoy these rants of a Snake Charmer...