Source code for pykml.factory

'''pyKML Factory Module

The pykml.factory module provides objects and functions that can be used to 
create KML documents element-by-element. 
The factory module leverages `lxml's ElementMaker factory`_ objects to create
KML objects with the appropriate namespace prefixes.

.. _lxml: http://lxml.de
.. _lxml's ElementMaker factory: http://lxml.de/objectify.html#tree-generation-with-the-e-factory
'''

from lxml import etree, objectify

nsmap={
    None: "http://www.opengis.net/kml/2.2",
    'atom': "http://www.w3.org/2005/Atom",
    'gx': "http://www.google.com/kml/ext/2.2",
}

# create a factory object for creating objects in the KML namespace
KML_ElementMaker = objectify.ElementMaker(
    annotate=False,
    namespace=nsmap[None],
    nsmap=nsmap,
)
# create a factory object for creating objects in the ATOM namespace
ATOM_ElementMaker = objectify.ElementMaker(
    annotate=False,
    namespace=nsmap['atom'],
    nsmap={'atom': nsmap['atom']},
)
# Create a factory object for the KML Google Extension namespace
GX_ElementMaker = objectify.ElementMaker(
    annotate=False,
    namespace=nsmap['gx'],
    nsmap={'gx': nsmap['gx']},
)

[docs]def get_factory_object_name(namespace): "Returns the correct factory object for a given namespace" factory_map = { 'http://www.opengis.net/kml/2.2': 'KML', 'http://www.w3.org/2005/Atom': 'ATOM', 'http://www.google.com/kml/ext/2.2': 'GX' } if namespace: if factory_map.has_key(namespace): factory_object_name = factory_map[namespace] else: factory_object_name = None else: # use the KML factory object as the default, if no namespace is given factory_object_name = 'KML' return factory_object_name
[docs]def write_python_script_for_kml_document(doc): "Generates a python script that will construct a given KML document" import StringIO from pykml.helpers import separate_namespace output = StringIO.StringIO() indent_size = 2 # add the etree package so that comments can be handled output.write('from lxml import etree\n') # add the namespace declaration section output.write('from pykml.factory import KML_ElementMaker as KML\n') output.write('from pykml.factory import ATOM_ElementMaker as ATOM\n') output.write('from pykml.factory import GX_ElementMaker as GX\n') output.write('\n') level = 0 xml = StringIO.StringIO(etree.tostring(doc)) context = etree.iterparse(xml, events=("start", "end", "comment")) output.write('doc = ') last_action = None main_element_processed_flag = False previous_list = [] # list of comments before the root element posterior_list = [] # list of comments after the root element for action, elem in context: # TODO: remove the following redundant conditional if action in ('start','end','comment'): namespace, element_name = separate_namespace(elem.tag) if action in ('comment'): indent = ' ' * level * indent_size if elem.text: text_list = elem.text.split('\n') if len(text_list) == 1: text = repr(elem.text) else: # len(text_list) > 1 # format and join all non-empty lines text = '\n' + ''.join( ['{indent}{content}\n'.format( indent=' '*(len(t)-len(t.lstrip())), content=repr(t.lstrip()) ) for t in text_list if len(t.strip())>0 ] ) + indent else: text = '' if level == 0: # store the comment so that it can be appended later if main_element_processed_flag: posterior_list.append("{indent}etree.Comment({comment})".format( indent = indent, comment = text, )) else: previous_list.append("{indent}etree.Comment({comment})".format( indent = indent, comment = text, )) else: output.write("{indent}etree.Comment({comment}),\n".format( indent = indent, comment = text, )) elif action in ('start'): main_element_processed_flag = True if last_action == None: indent = '' else: indent = ' ' * level * indent_size level += 1 if elem.text: # METHOD 1 # # treat all text string the same. this works but gets # # messy for multi-line test strings # text = repr(elem.text) # METHOD 2 - format multiline strings differently text_list = elem.text.split('\n') if len(text_list) == 1: text = repr(elem.text) else: # len(text_list) > 1 # format and join all non-empty lines text = '\n' + ''.join( ['{indent}{content}\n'.format( indent=' '*(len(t)-len(t.lstrip())), content=repr(t.lstrip()) ) for t in text_list if len(t.strip())>0 ] ) + indent else: text = '' output.write('{indent}{factory}.{tag}({text}\n'.format( indent = indent, factory = get_factory_object_name(namespace), tag = element_name, text = text, )) elif action in ('end'): level -= 1 if last_action == 'start': output.pos -= 1 indent = '' else: indent = ' ' * level * indent_size for att,val in elem.items(): output.write('{0} {1}="{2}",\n'.format(indent,att,val)) output.write('{0}),\n'.format(indent)) last_action = action # remove the last comma output.pos -= 2 output.truncate() output.write('\n') for entry in previous_list: output.write('doc.addprevious({entry})\n'.format( entry=entry )) for entry in posterior_list: output.write('doc.addnext({entry})\n'.format( entry=entry )) # add python code to print out the KML document output.write('print etree.tostring(etree.ElementTree(doc),pretty_print=True)\n') return output.getvalue()