Expressions are used in import rules and style sheets.

Use in style sheets

They are used in <if> and <condition> elements. You write them using the exp attribute. For example:

<if exp='scale > 50000'>
<condition exp='$="Italy"'>

You can use the following special variables in style sheet expressions:

$ = the object's label

  • @ = map object type: 0=point, 1=line, 2=polygon, 3=array (texture)
  • @type is the same as @
  • @layer = style sheet layer the object belongs to
  • @id = the object's ID within the CTM1 file; equal to its byte offset in the file
  • @feature_type, @feature_type_name, @sub_type, @level, @speed_limit, @bridge, @tunnel, @one_way, @one_way_forward, @one_way_backward, @drive_on_left, @roundabout, @toll, @gradient, @private, @pedestrian_access, @cycle_access, @motor_vehicle_access, @emergency_vehicle_access, @other_access and @wrong_way give access to the feature info attributes.

For example:

<condition exp='@feature_type== "cit"'>

Route feature types must be one of the following: motorway, motorway link, trunk road, trunk road link, primary road, primary road link, secondary road, secondary road link, tertiary road, unclassified road, residential road, track, service road, pedestrian road, vehicular ferry, passenger ferry, living street, cycleway, path, footway, bridleway, steps, road, unpaved road, railway, light railway, subway, aerial way, ski downhill, ski nordic, waterway, unknown route. Letter case and spaces are ignored when comparing names: 'Motorway' is the same as 'motorway'.

Here is a style sheet condition to select trunk roads:

<condition exp='@feature_type=="trunk road"'/>

Use in import rules

They are used in the test or else attribute of any statement.


Expressions support most C++, Java or JavaScript operators, but there are some extensions and differences:

  • You can use and, or, bitand, bitor, le, lt, eq, gt and ge instead of &&, ||, &, |, <=, <, ==, > and >=. This is especially useful where XML makes it hard to use & and <, for which you have to substitute & and <. The operator = means the same as ==.
  • There are special equality operators to ignore case (eqc), ignore case and accents (eqa), use fuzzy matching (eqf), and use wild cards (eqw).
  • The operators in and notin work with sets and ranges. A set is a comma-separated list enclosed in { }, and a range is a comma-separated pair of items enclosed in [ ], giving inclusive lower and upper bounds. The in and notin operators have the same precedence as comparison operators..
  • There is a string concatenation operator written as two full stops: ..
  • Strings are automatically converted to numeric values where needed. Thus, 3 == '3' is true, and so is 256 == '0x100'. We extend that by converting 3-letter strings to type codes used in CartoType, as in @feature_type=='cit'. When two strings are compared, however, they don't need to be converted, and the comparison is lexicographic.
  • Identifiers are attribute names. The identifier Type, in style sheet expressions, refers to the integer attribute. Other identifiers refer to string attributes.
  • In style sheets the special identifier @ refers to the object type: 0=point, 1=line, 2=polygon, 3=array (e.g., terrain). So you can write a <condition> to select polygon objects only: <condition exp="@=2">.
  • In import rules @node means 'in a node', @way means 'in a way', @relation means 'in a relation'; and @ is undefined
  • Strings can be delimited using ' or ". Inside a string delimited with ', the escape sequences \' and \\ can be used for ' and \. Inside a string delimited with " the escape sequences \" and \\ can be used for " and \. There are no other escape sequences. You cannot use ' for ', because it is converted to ' by the XML parser before it gets to CartoType's expression parser. Obviously, if you delimit the entire expression with double quotes, you have to use single quotes for strings inside the expression, and vice versa.

Here are the operators in order of evaluation:

( ) - brackets enclosing a sub-expression

unary operators: + (unary plus), - (unary minus), ~ (bitwise not), and ! (logical not)

multiplicative operators: * (multiply), / (divide), % (modulo)

additive operators: + (plus), - (minus), .. (string concatenation)

shift operators: << (left shift), >> (right shift)

comparison operators: lt or < (less), le or <= (less or equal), eq or = or == (equal), neq or != (not equal), ge or >= (greater or equal), gt or > (greater), eqc (equal, ignoring case), eqa (equal, ignoring accents and case), eqf (equal using fuzzy matching), eqw (equal using wild cards)

range and set operators (same priority as comparison operators): in { a, b, ... } (in a set), notin { a, b, ... } (not in a set), in [ low, high ] (in a range), notin [ low, high ] (not in a range)

bitwise operators: bitand or & (bitwise and), bitor or | (bitwise or), xor or ^ (bitwise exclusive or)

logical operators: and or && (and), or or || (or)

Undefined variables

Comparisons for greater, less, greater than or equal, and less than or equal always return false for undefined variables. Therfore tests like 'population gt 0' or 'population le 250', both of which are used in the standard OSM import rules, return true only when attribute 'population' exists in a map object.

Comparisons for equality are subtle, but do what is usually expected. If var is undefined, 'var==0' returns false, but 'var==""' returns true. Thus the empty string is treated as the same as 'undefined', while 0, or any other number, is not the same as 'undefined'.

Logical tests

Logical tests, also called boolean or true-false tests, work like this: the value true is returned for all strings except the empty string, and for all numbers except 0. Undefined variables have the logical value 'false'. That allows you to test for the existence of an OSM attribute in import rules, or a map object string attribute in a style sheet, using an expression consisting of the variable name only, like 'var'.