Vancouver XML Users Group

I’ll be presenting on Renaissance, OS X, and Python at the VanX meeting at 6:30 p.m. on Thursday, December 16th. By then I should have a lot more programs and utilities to show.

Hello Renaissance

In my last post I promised a Hello World program for PyObjC + Renaissance. If you haven’t got those installed, or aren’t sure, please check out the prerequisites.

We’ll be creating four files, each of which will be a template for upcoming examples. The menus will be defined in MainMenu.gsmarkup, the application window will be in MainWindow.gsmarkup, the application code will be in hello.py, and the py2app build script will be in setup.py. There is no reason that the menus and window have to be separated this way, but it will serve as an example for later, more complex applications, when you’ll want to load in code from multiple files.

MainMenu.gsmarkup

<?xml version="1.0"?>
<!DOCTYPE gsmarkup>
<gsmarkup>
    <objects>
        <menu type="main">
            <menu title="Hello World" type="apple">
                <menuItem title="About Hello World"
                action="orderFrontStandardAboutPanel:"/>
                <menuSeparator/>
                <menu title="Services" type="services"/>
                <menuSeparator/>
                <menuItem title="Hide Hello World" action="hide:" key="h"/>
                <menuItem title="Hide Others" action="hideOtherApplications:"/>
                <menuItem title="Show All" action="unhideAllApplications:"/>
                <menuSeparator/>
                <menuItem title="Quit Hello World" action="terminate:" key="q"/>
            </menu>
            <menu title="Edit">
                <menuItem title="Cut" action="cut:" key="x"/>
                <menuItem title="Copy" action="copy:" key="c"/>
                <menuItem title="Paste" action="paste:" key="v"/>
                <menuItem title="Delete" action="delete:"/>
                <menuItem title="Select All" action="selectAll:" key="a"/>
            </menu>
            <menu title="Window" type="windows">
                <menuItem title="Minimize Window" action="performMiniatureize:"
                key="m"/>
                <menuSeparator/>
                <menuItem title="Bring All to Front" action="arrangeInFront:"/>
            </menu>
        </menu>
    </objects>
</gsmarkup>

MainWindow.gsmarkup

<?xml version="1.0"?>
<!DOCTYPE gsmarkup>
<gsmarkup>
    <objects>
        <window title="Hello World" closable="NO" >
            <vbox>
                <label>Hello World!</label>
                <button title="Click this button to quit" action="terminate:"/>
            </vbox>
        </window>
    </objects>
</gsmarkup>

hello.py

from Foundation import *
from AppKit import *
from Renaissance import *
class MyApplicationDelegate(NSObject):

    def cut_(self, sender):
        pass

    def applicationDidFinishLaunching_(self, notification):
        NSBundle.loadGSMarkupNamed_owner_('MainWindow', self)

def main():
    app = NSApplication.sharedApplication()
    delegate = MyApplicationDelegate.alloc().init()
    app.setDelegate_(delegate)
    NSBundle.loadGSMarkupNamed_owner_('MainMenu', delegate)
    NSApp().run()
if __name__ == '__main__': main()

setup.py

'''
Minimal setup.py example, run with:
% python setup.py py2app
'''
from distutils.core import setup
import py2app
setup(
    data_files = ['MainMenu.gsmarkup', 'MainWindow.gsmarkup'],
    app = ['hello.py'],
)

Commentary

OK, so 80 lines of code may seem excessive for a Hello World program. We could certainly do it in less, perhaps 20 total lines of Python and Renaissance. But what we have here is a complete working Cocoa application which behaves properly to standard keyboard shortcuts, supports services, etc. And that’s not bad for 80 lines of code.

DOM back to XML in Python

OK, time to crank up to speed, it’s been a lot longer than I intended between posts.

In the last episode we learned how to initialize many of the DOMs and DOM-like tools for Python from an XML document. Today we’re going to see how to convert these back to XML from the DOM. So fasten your seatbelts and let’s go.

import domParse
from xml.dom.ext.c14n import Canonicalize
def stringMinidom(filename):
    return Canonicalize(domParse.parseMinidom(filename))

def string4Dom(filename):
    return Canonicalize(domParse.parse4Dom(filename))

def stringDomlette(filename):
    return Canonicalize(domParse.parseDomlette(filename))

def stringLibXml(filename):
    # pretty-printed, which may not be what you want,
    # depending on the XML in question
    return domParse.parseLibXml(filename).serialize(encoding='utf-8', format=True)
    # 4DOM c14n breaks because libXML doesn't give you a DOM
    # return Canonicalize(domParse.parseLibXml(filename))

def stringPxDom(filename):
    import pxdom
    serializer = pxdom.LSSerializer()
    return serializer.writeToString(domParse.parsePxDom(filename))
    #return Canonicalize(domParse.parsePxDom(filename))

def main(filename):
    print '4DOM:', string4Dom(filename)
    print 'Domlette:', stringDomlette(filename)
    print 'MiniDom:', stringMinidom(filename)
    print 'LibXml:', stringLibXml(filename)
    print 'PxDom:', stringPxDom(filename)
if __name__ == '__main__': main(domParse.small_filename)

As you can see, there’s not much to it. This codes does require that you’ve installed the PyXML package, but if you’re serious about XML in Python, that will already be the case. In our next outing we can explore some of the less DOM-like, but more Pythonic ways to play with XML.

PyXML: http://pyxml.sourceforge.net/

4Suite: http://4suite.org/index.xhtml

libxml: http://www.xmlsoft.org/ (instructions for the python bindings are linked from this page)

pxdom: http://www.doxdesk.com/software/py/pxdom.html

You may now return your trays to their upright positions.

Initializing a DOM in Python

There are many DOM options in Python, and I have trouble remembering how to load a document into the various DOMs. Here are a few common ones, although there are many variations on them (loading from URL or string, different configurations, etc.). This should provide a starting point.

# Examples for reading in various DOMs from an XML file
# MiniDOM
def parseMinidom(filename):
    try:
        from xml.dom.minidom import parse
        doc = parse(filename)
        return doc
    except Exception, e:
        return 'parseMinidom() failed with exception %s' % e
# 4DOM
def parse4Dom(filename):
    try:
        from xml.dom.ext.reader.Sax2 import Reader
        f = file(filename)
        reader = Reader(validate=0, keepAllWs=0, catName=None)
        doc = reader.fromStream(f) # slow!
        f.close()
        return doc
    except Exception, e:
        return 'parse4Dom() failed with exception %s' % e
# Domlette
def parseDomlette(filename):
    try:
        from Ft.Xml.Domlette import NonvalidatingReader as reader
        f = file(filename)
        uri = 'file:///%s' % filename # suppress warning
        doc = reader.parseStream(f, uri)
        f.close()
        return doc
    except Exception, e:
        return 'parseDomlette() failed with exception %s' % e
# libXml
def parseLibXml(filename):
    try:
        import libxml2
        f = file(filename)
        data = f.read()
        f.close()
        doc = libxml2.parseDoc(data)
        return doc
    except Exception, e:
        return 'parseLibXml() failed with exception %s' % e
# pxDom
def parsePxDom(filename):
    try:
        import pxdom
        doc = pxdom.parse(filename)
        return doc
    except Exception, e:
        return 'parsePxDom() failed with exception %s' % e
def main():
    import sys
    filename = sys.argv[1]
    print '4DOM:', parse4Dom(filename)
    print 'Domlette:', parseDomlette(filename)
    print 'MiniDom:', parseMinidom(filename)
    print 'LibXml:', parseLibXml(filename)
    print 'PxDom:', parsePxDom(filename)
if __name__ == '__main__': main()

« Previous Page « Previous Page Next entries »

google

google

asus