KML keyhole markup language
2.2 · Placemark profile We-Fly

Interactive specification

KML, minus the parts that draw.

KML is a presentation language — it describes how a map should look, and only incidentally where things are. Free flight uses the small part that carries positions: Placemark, Point, and a coordinate tuple whose field order catches everyone exactly once.

XML, UTF-8 lon,lat,ele — in that order Nested containers Placemark points
01 Overview

A drawing language with positions in it

KML — Keyhole Markup Language — was Google Earth's native format and became an OGC standard in 2008. Its subject is presentation: icons, line styles, balloon popups, camera positions, time sliders, ground overlays. Geographic positions are in there because you have to say where to draw things.

That framing explains everything awkward about using KML for waypoints. Free-flight tools want a list of named places; KML offers a tree of styled features that happens to contain some. The subset that carries what we want is small:

ElementRole
<Placemark>A named feature. The waypoint.
<Point>Its geometry, when it is a single position.
<coordinates>The position itself — and the one thing on this page to get right.
<name>, <description>The two text slots.
<Document>, <Folder>Containers. They nest, arbitrarily deep.
KMZ is a zip archive. A .kmz is a zipped KML plus its icons and overlays, with the KML conventionally at doc.kml. It is what Google Earth saves by default, so pilots hand it over constantly. It is not text — unzip first, or tell the pilot to export "KML" rather than "KMZ".
02 Coordinates

lon,lat,ele — in that order

A KML coordinate tuple is comma-separated, longitude first:

one point
<Point><coordinates>5.635000,44.278000,1320</coordinates></Point>
              ↑ longitude  ↑ latitude  ↑ elevation, metres
Longitude first. The opposite of how coordinates are spoken, written on charts, and stored in GPX's lat/lon attributes — and the same order as GeoJSON, which is where the convention comes from. Swap them and a French waypoint lands in Somalia. There is no hemisphere letter and no unit to catch it: both numbers are plausible on their own.
PositionValueRangeNotes
1Longitude−180 … 180Signed decimal degrees, WGS84.
2Latitude−90 … 90Signed decimal degrees, WGS84.
3ElevationmetresOptional. Interpreted per <altitudeMode>; defaults to clampToGround, which ignores it entirely.

Whitespace separates tuples, commas separate fields

A <LineString> holds many tuples in one element, separated by any whitespace — and real files wrap them across lines with generous indentation:

a route as a LineString
<LineString><coordinates>
  5.635000,44.278000,1320
  5.740000,44.285000,1834
  5.715000,44.362000,1420
</coordinates></LineString>

So: split the element's text on whitespace to get tuples, then split each tuple on commas. Splitting on "comma or whitespace" in one pass works for a single point and silently scrambles a LineString.

Try it · coordinate tuple → position
03 Document shape

Containers that nest

waypoints.kml
<?xml version="1.0" encoding="UTF-8"?>
<kml xmlns="http://www.opengis.net/kml/2.2">
  <Document>
    <name>Chabre waypoints</name>
    <Folder>
      <name>Launches</name>
      <Placemark>
        <name>D01188</name>
        <description>Chabre launch</description>
        <Point><coordinates>5.635000,44.278000,1320</coordinates></Point>
      </Placemark>
    </Folder>
    <Placemark>
      <name>Landing field</name>
      <Point><coordinates>5.826000,44.319000,560</coordinates></Point>
    </Placemark>
  </Document>
</kml>

<Document> and <Folder> are both containers, both optional, and both nest inside each other to any depth. A <Placemark> can sit at any level — including directly under <kml>.

Recurse; never assume a depth. Google Earth groups waypoints into folders by whatever the user dragged around, so the same collection can arrive one level deep from one pilot and four from another. Walk the whole tree collecting every <Placemark> that has a <Point> — a fixed kml → Document → Placemark path finds nothing in half of real files.

Placemarks that are not waypoints

A <Placemark> can hold a <LineString>, a <Polygon>, a <MultiGeometry> or no geometry at all. For a waypoint importer, require <Point> and skip the rest — an airspace polygon or a drawn track is not a waypoint, and a Placemark with only a description is a text label.

04 Element explorer

The elements that carry meaning

KML defines several hundred elements. These are the ones that survive a waypoint round trip; everything else is presentation.

05 Codes & names

Two slots, and HTML in one of them

Like GPX and OziExplorer, KML gives a feature two text slots. The comp convention is the same:

ElementCarries
<name>The codeB61130, D01188
<description>The full name

Promote <name> to a code when it is 2–8 alphanumeric characters with at least one digit and the description holds something different. The digit requirement stops Goal and Home being read as codes.

The KML-specific complication

<description> is rendered as HTML in Google Earth's balloon popup. So it frequently is HTML, usually wrapped in CDATA:

a description you will actually meet
<description><![CDATA[
  <b>Chabre launch</b><br/>
  Alt 1320 m &middot; <a href="https://example.org">site guide</a>
]]></description>
Treat the description as untrusted markup. Take its text content, strip tags, and bound the length before you store or display it. Rendering it as HTML because KML says it is HTML puts arbitrary markup from an uploaded file into your page.
Try it · name + description → code, name
06 File inspector

Paste a KML, read the waypoints

The whole container tree is walked, every <Placemark> with a <Point> is decoded, and coordinates are shown in the order KML wrote them and the order you think in. Nothing is uploaded.

KML source · editable
Parsed live
07 Parsing gotchas

Where KML goes wrong

  • Longitude comes first. Nothing in the file will tell you when you have it backwards.
  • Commas separate fields, whitespace separates tuples. Two splits, in that order.
  • Recurse into Document and Folder, to any depth, and handle several of either at the same level.
  • Require <Point>. Placemarks also hold LineStrings, Polygons and MultiGeometries.
  • Elevation is optional and often meaningless. The default altitudeMode is clampToGround, which discards it — a third field of 0 usually means "not supplied".
  • <description> is HTML in CDATA. Strip tags, bound the length, never render it raw.
  • KMZ is a zip. Unzip and read doc.kml, or refuse it with a message that explains the difference.
  • Namespaces vary and gx: extensions abound. Google's gx:Track, gx:altitudeMode and friends sit in their own namespace. Match local names, ignore what you do not know.
08 In We-Fly

What We-Fly reads and writes

SurfaceReadsWrites
XC planner — collectionsEvery <Placemark> with a <Point>, at any depthOne <Document>, one <Placemark> per waypoint
XC planner — routes
Flight upload

Parsing happens entirely in the browser; an imported collection is only stored when you explicitly save it. Files are written as KML 2.2 with six decimal places of coordinate precision (≈ 0.1 m), MIME type application/vnd.google-earth.kml+xml. Competition codes round-trip through the two text slots.

KML is never accepted as a flight track — even though instruments like Flymaster offer it. Every flight enters We-Fly as IGC, which carries pressure altitude and a security record that KML has no way to express. If a service only offers you KML for a flight, ask them for the original IGC; they almost always still have it.

The same collections also round-trip through the three .wpt dialects, GPX and SeeYou .cup.

09 Sources

What this reconciles