zgeo.kml/Collections

Getting kml documents from folders and objects is nice. Getting it from Plone collections would add more flexibility.

In order to get that to work, several changes were necessary. This was because the Document class uses self.context.values() to get the contents of the folder. That does not work for Collections. There you have to access self.context.queryCatalog(). That returns a list of brains, that can be converted to the actual object through getObject(). Those object do expose the ICMFDublinCore fields.

In a Collection you can have all kinds of objects and some of them could not be 'adapted' to ICMFDublinCore. So I added an exception handling block around that.

Which means that the Class now looks like this:

class CollectionDocument(Document):
    """A class that gets its features from the catalog
    """

    implements(IContainer)
    __name__ = 'kml-collection-document'
    template = NamedTemplate('template-kml-document')

    def __init__(self, context, request):
        self.context = context
        self.request = request

    @property
    def features(self):
        for ob in self.context.queryCatalog():
            item = ob.getObject()
            if item is not None:
                try:
                    self.context.plone_log(item.title)
                    yield Placemark(item, self.request)
                except TypeError:
                    continue #('Could not adapt', <ATBTreeFolder at /plone/news>, <InterfaceClass zo
pe.dublincore.interfaces.ICMFDublinCore>)
            else:
                continue


    def __call__(self):
        return self.template().encode('utf-8')

To get the right class called I modified the configure.zcml as follows:

<configure
  xmlns="http://namespaces.zope.org/zope"
  xmlns:five="http://namespaces.zope.org/five"
  xmlns:browser="http://namespaces.zope.org/browser"
  >
  <include package="zope.app.component" file="meta.zcml"/>
  <include package="zope.app.security" file="meta.zcml"/>
  <include package="zope.app.security"/>

  <browser:page
    for="Products.ATContentTypes.content.topic.ATTopic"
    name="kml-document"
    class=".browser.CollectionDocument"
    permission="zope.View"
    />

  <browser:page
    for="*"
    name="kml-document"
    class=".browser.Document"
    permission="zope.View"
    />

  <adapter
    factory=".browser.document_template"
    for=".browser.Document"
    name="template-kml-document"
    />

</configure>

In the template the view/name did not work for Collections so that needed to be changed to:

    <name tal:content="context/title">TITLE</name>

Finally I had an error with a wrong Polygon coordinate entry, so I edited the coords_to_kml, to be able to handle situations like that:

def coords_to_kml(geom):
    gtype = geom.type
    if gtype is not None:
        if gtype == 'Point':
            coords = (geom.coordinates,)
        elif gtype == 'Polygon':
            coords = geom.coordinates[0]
        else:
            coords = geom.coordinates
        try:
            if len(coords[0]) == 2:
                tuples = ('%f,%f,0.0' % tuple(c) for c in coords)
            elif len(coords[0]) == 3:
                tuples = ('%f,%f,%f' % tuple(c) for c in coords)
            else:
                raise ValueError, "Invalid dimensions"
            return ' '.join(tuples)
        except TypeError:
            raise TypeError, "Coordinate data entry error (A polygon with point co-ordinates? Bracke
ts?)"
    else:
        return ''

I did not get around to writing tests yet as zgeo.kml seems to be aimed at Zope3.

I did do some tests on my system, and what results is a kml file of all the items in the Collection that can be adapted to ICMFDublinCore (so not folders, not news, and so on). If it is not georeferenced than there will be no coordinates, but it is still in the kml file.

Update for Large Folders:

In zgeo.plone.kml/zgeo/plone/kml/configure.zcml add the following:

  <browser:page
    for="Products.ATContentTypes.content.folder.ATBTreeFolder"
    name="kml-document"
    class=".browser.ATBTreeFolder"
    permission="zope.View"
    />

And in zgeo.plone.kml/zgeo/plone/kml/browser.py:

class ATBTreeFolder(Document):

    @property
    def features(self):
        for object in self.context.folderContents():
            yield Placemark(object, self.request)

Attachments