1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 181 182 183 184 185 186 187 188 189 190 191 192 193 194 195 196 197 198 199 200 201 202 203 204 205 206 207 208 209 210 211 212 213 214 215 216 217 218 219 220 221 222 223 224 225 226 227 228 229 230 231 232 233 234 235 236 237 238 239 240 241 242 243 244 245 246 247 248 249 250 251 252 253 254 255 256 257 258 259 260 261 262 263 264 265 266 267 268 269 270 271 272 273 274 275 276 277 278 279 280 281 282 283 284 285 286 287 288 289 290 291 292 293
|
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 <name> 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]: '<Placemark xmlns:gx="http://www.google.com/kml/ext/2.2" xmlns:atom="http://www.w3.org/2005/Atom" xmlns="http://www.opengis.net/kml/2.2"><name>Hello World!</name><Point><coordinates>-64.5253,18.4607</coordinates></Point></Placemark>'
# 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 = '<kml xmlns="http://www.opengis.net/kml/2.2">' \
....: '<Document>' \
....: '<Folder>' \
....: '<name>sample folder</name>' \
....: '</Folder>' \
....: '</Document>' \
....: '</kml>'
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 (`<gx_Tour>`) 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 <eggplant> is not a valid OGC KML element
In [62]: bad_kml_str = '<kml xmlns="http://www.opengis.net/kml/2.2">' \
....: '<Document>' \
....: '<Folder>' \
....: '<eggplant/>' \
....: '</Folder>' \
....: '</Document>' \
....: '</kml>'
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.
|