Level0L file is a plain text file with a stream of objects. Each object starts with a header: <type> <id>, where type can be "node", "way", "relation" or "changeset". Identifier is a positive integer number. It can have an optional version number after a dot: 123.4 means ID=123, version=4. But usually version numbers are hidden on a server or in other storage.
Nodes must have latitude and longitude values after a colon:
node <ID>: <lat>, <lon>
Comments are allowed in the header or taking the whole line: they start with '#'.
A body of an element contains tags and references in no particular order. Tags are written as is:
<tag> = <value>
Whitespace is irrelevant, the only character that matters is an equals sign ('='). If a key contains an equals sign, it must be escaped with backslash ('\='). If a key starts with '#', it must be indented with at least one space.
References are written as <type> <id>, not unlike headers, but in this case type should be one of "nd", "wy" or "rel". This way references could be distinguished from headers. The order of referenced objects matters. For relation members, a role can be added at the end:
<type> <id> [<role>]
There are no reqiurements for whitespace, order and style, but there are some guidelines for better readability:
- version numbers should not appear in headers;
- tags and references should be indented with two spaces;
- tags should precede references;
- tags should have spaces before and after '=' sign;
- objects with tags and/or references should be followed by an empty line, but no gaps otherwise.
Level0L format is for editing data, therefore it contains means for modifying objects. Every base object state (e.g. hash, or a canonical representation) should be stored on a server, so it could determine which objects were modified. There is no sign in l0l to mark modified objects.
New objects either do not have identifiers (so a header could be a single word with an object type), or have negative identifiers.
Deleted object headers should be prefixed with a minus sign ('-'). No information besides object type and its identifier is needed, and can be omitted.
If a header is prefixed with '!' character, it was modified before a newer version has been downloaded. Usually the contents are replaced or merged with newer version data, and old changes are stored somewhere near it in comments. After resolving conflicts you should delete '!' prefixes.
When the code contains "changeset" object, its tags would be appended to the uploaded changeset: this would be an alternative way of specifying changeset comment, and also a way of adding changeset source. The object should have no version, and there can be only one such object.
This is a l0l-ized example from this section:
node 298884269.1: 54.0901746, 12.2482632 # made by user SvenHRO (46882) in changeset 676636 on 2008-09-21T21:37:45Z node 261728686: 54.0906309, 12.2441924 # versions should be stored server-side node 1831881213: 54.0900666, 12.2539381 # comments are not allowed in tag values, '=' is screened (\=) only in keys name = Neu Broderstorf traffic_sign = city_limit ... node 298884272: 54.0901447, 12.2516513 way 26659127.5 nd 292403538 nd 298884289 ... nd 261728686 highway = unclassified name = Pastower Straße relation 56688.28 # member types: nd, wy, rel; roles are put after ids nd 294942404 ... nd 364933006 wy 4579143 forward ... nd 249673494 name = Küstenbus Linie 123 network = VVW operator = Regionalverkehr Küste ref = 123 route = bus type = route ...
Another example from JOSM file format with optional parts omitted:
node 26821100: 51.5077286, -0.1279688 created_by = Potlatch 0.10f name = Nelson's Column tourism = attraction monument = statue historic = monument node: 51.507661490456606, -0.1278000843634869 -node 346364767