pyKML Tutorial ============== The following tutorial gives a brief overview of many of the features of pyKML. It is designed to run from within a Python or iPython shell, and assumes that pyKML has been installed and is part of your Python search path. The tutorial is designed to be followed from start to finish. For complete stand alone programs that demonstrate how to use pyKML, check out the :doc:`examples`. Constructing KML from scratch ----------------------------- The pyKML library can be used to construct KML documents, using the :ref:`pykml-factory` module: .. ipython:: # create a factory object that can create elements in the KML namespace In [11]: from pykml.factory import KML_ElementMaker as KML # create an the object equivalent of a KML element In [12]: name_object = KML.name("Hello World!") If you are creating KML documents that utilize elements that are not part of the default KML namespace, you will want to create an additional factory objects for each namespace. For example, the following creates factory objects that can be used to create elements that are part of the ATOM and Google Extensions namespace: .. ipython:: In [13]: from pykml.factory import ATOM_ElementMaker as ATOM In [14]: from pykml.factory import GX_ElementMaker as GX Documents with nested KML tags can be created by nesting the creation of Python objects: .. ipython:: In [16]: pm1 = KML.Placemark( ....: KML.name("Hello World!"), ....: KML.Point( ....: KML.coordinates("-64.5253,18.4607") ....: ) ....: ) Once a pyKML object element has been created, a string representation can be generated by using the `.tostring()` method: .. ipython:: In [21]: from lxml import etree @doctest In [22]: etree.tostring(pm1) Out[22]: 'Hello World!-64.5253,18.4607' # use the pretty_print keyword if you want something more readable In [23]: print etree.tostring(pm1, pretty_print=True) pyKML creates Python objects, which can be passed around and later aggregated. The following creates a second placemark object, and then groups the two placemarks together in a folder. .. ipython:: # create another placemark In [31]: pm2 = KML.Placemark( ....: KML.name("A second placemark!"), ....: KML.Point( ....: KML.coordinates("-64.5358,18.4486") ....: ) ....: ) # group the two placemarks in a folder In [32]: fld = KML.Folder(pm1,pm2) In [33]: print etree.tostring(fld, pretty_print=True) Objects representing KML elements can also be appended into objects that have already been created. For example, the following appends yet another placemark to the folder. .. ipython:: # create yet another placemark In [41]: pm3=KML.Placemark(KML.name("A third placemark!")) # append the placemark to the series already in the folder In [42]: fld.append(pm3) In [43]: print etree.tostring(fld, pretty_print=True) Similarly, you can remove elements from an existing object. The following removes the second of three placemarks from the folder: .. ipython:: # remove a particular placemark In [51]: fld.remove(pm2) In [52]: print etree.tostring(fld, pretty_print=True) Once you have a KML document, you can access elements using object attributes: .. ipython:: In [55]: print fld.Placemark.name.text This type of attribute-based access is provided by the `lxml` packages's `objectify API`. pyKML users are encouraged to familiarize themselves with the `objectify API documentation`_ on the lxml website, because pyKML inherits this functionality. .. _objectify API documentation: http://lxml.de/objectify.html Parsing existing KML documents ------------------------------ Sometimes instead of building a KML document from scratch, you may want to modify an existing KML document. For this case, pyKML's parsing capabilities are useful. pyKML can parse information from a variety of sources, including strings, local files, and remote URLs. The most straightforward is parsing from a string... .. ipython:: In [61]: from pykml import parser In [62]: kml_str = '' \ ....: '' \ ....: '' \ ....: 'sample folder' \ ....: '' \ ....: '' \ ....: '' In [63]: root = parser.fromstring(kml_str) In [64]: print root.Document.Folder.name.text You can also parse a local file... .. ipython:: In [71]: from os import path In [72]: kml_file = path.join( \ ....: '../src/pykml/test', \ ....: 'testfiles/google_kml_developers_guide', \ ....: 'complete_tour_example.kml') In [73]: with open(kml_file) as f: In [74]: doc = parser.parse(f) In [75]: ... or a remote URL... .. ipython:: In [80]: import urllib2 In [81]: url = 'http://code.google.com/apis/kml/documentation/KML_Samples.kml' In [82]: fileobject = urllib2.urlopen(url) In [83]: root = parser.parse(fileobject).getroot() In [84]: print root.Document.name Validation of KML documents --------------------------- KML documents that you create can be validated against XML Schema documents, which define the rules of which elements are acceptible and what ordering can be used. Both the OGC KML schema and the Google Extension schemas are included with pyKML. To validate your KML document, first create instances of the schemas: .. ipython:: In [100]: from pykml.parser import Schema In [101]: schema_ogc = Schema("ogckml22.xsd") In [102]: schema_gx = Schema("kml22gx.xsd") Then use the schemas to validate your KML objects, using the `.validate()` or `.assertValid()` methods. The following code creates a small invalide KML document which includes an element from the Google Extension namespace (``) so the document does not validate against the basic OGC KML schema, but does validate agains the Google Extensions schema. .. ipython:: # create a small KML document In [110]: doc = KML.kml(GX.Tour()) # validate it against the OGC KML schema In [111]: schema_ogc.validate(doc) # validate it against the Google Extension schema In [112]: schema_gx.validate(doc) The `.validate()` method only returns True or False. For invalid documents, it is often useful to obtain details of why the document is invalid using the `.assertValid()` method: .. ipython:: # validate against the OGC KML schema, and generate an exception In [113]: schema_ogc.assertValid(doc) You can also validate while parsing by including a schema object as a parameter. .. ipython:: # the following triggers an error because is not a valid OGC KML element In [62]: bad_kml_str = '' \ ....: '' \ ....: '' \ ....: '' \ ....: '' \ ....: '' \ ....: '' In [63]: root = parser.fromstring(bad_kml_str, schema_ogc) Setting the Number of Decimal Places ------------------------------------ Many KML files, especially those authored by Google Earth, contain coordinate information with more decimal places that often is necessary. The `set_max_decimal_places()` function addresses this, by allowing a user to reduce the number of decimal places used. The example below demonstrates this for a previously created placemark. .. ipython:: In [70]: from pykml.helpers import set_max_decimal_places In [71]: print etree.tostring(pm1, pretty_print=True) # set the coordinate precision to something smaller In [72]: set_max_decimal_places( ....: pm1, ....: max_decimals={ ....: 'longitude': 2, ....: 'latitude': 1, ....: } ....: ) # note that the coordinate values have changed In [73]: print etree.tostring(pm1, pretty_print=True) Building pyKML Python Scripts ----------------------------- While pyKML allows you use leverage programming to create customized KML files, writing the initial pyKML code can be tedious. To help with this, pyKML provides the verbosely named `.write_python_script_for_kml_document()` function which will produce a Python script that can serve as a starting point for further customization. .. ipython:: In [10]: from pykml.factory import write_python_script_for_kml_document In [11]: url = 'http://code.google.com/apis/kml/documentation/kmlfiles/altitudemode_reference.kml' In [12]: fileobject = urllib2.urlopen(url) In [13]: doc = parser.parse(fileobject).getroot() In [14]: script = write_python_script_for_kml_document(doc) In [15]: print script That concludes the tutorial. For further examples of how pyKML can be used, head on over to the :doc:`examples` section of the documentation.