Sometimes you need the power of a full programming language when importing data. For example, you might need to load an ESRI shapefile, read records with a matching key in an associated DBF file, and loop through the records. The ChaiScript language, which can be used anywhere suitable in a CartoType makemap file inside the element <script> ... </script>, allows you to do that. It's very similar to C++, with some differences (e.g., 'int x = 0' in C++ becomes 'auto x = int(0)' in ChaiScript; there are no postincrement or postdecrement operators; etc.). This article explains the functions added to ChaiScript to make data import possible. General notes on the ChaiScript language are found on another page

Here's a simple example:

<?xml version="1.0" encoding="UTF-8"?>
<CartoTypeImportRules>
        <file name='sg.shp'>
        <dbf name='si.dbf' prefix='SI_' key='ID'/>   

        <script>

        <![CDATA[
            set("name",in("JNCTID"));
            auto n = dbf_record_count("SI_");
            for (auto i = 0; i < n; ++i)
                {
                auto attrib_name = "txt" + to_string(i);
                set(attrib_name,in("SI_TXTCONT",i));
                }
            commit("sign");
        ]]>
        </script>
    </file>
</CartoTypeImportRules>

Notes:

The <![CDATA[ ... ]]> construct allows the use of raw text including < and > signs, etc., without interfering with the XML parser. If you don't use CDATA you need to use things like &lt;, &gt;, etc.

The functions set() (set an attribute), in() (get an input field), and commit() (commit an output map object) allow you to interact with the input record and create output map objects in the same way as in a normal .makemap file.

The function dbf_record_count() takes the prefix you've assigned to the DBF file and finds the number of records for the current key for that file.

Built-in constants, variables and functions

The following built-in constants, variables and functions allow you to import data. They supply the same functionality as the ordinary XML-based import language.

Constants

POINT has the value 0 and can be used when setting a map object type using object_type.

LINE has the value 1 and can be used when setting a map object type using object_type.

POLYGON has the value 2 and can be used when setting a map object type using object_type.

Variables

attribute is a writable variable containing the current object's integer attribute.

layer is a writable variable containing the current object's layer name, which must be a string

object_type is a writable variable containing the object type, which must be an integer

Functions

commit() writes a new map object to the output with the current layer (the layer variable), OSM type, object type (the object_type variable) and attributes (the integer attribute is taken from the attribute variable).

commit(string aLayer) writes a new map object to the output with the layer aLayer and the current OSM type, object type and attributes.

commit(string aLayer,string aOsmType) writes a new map object to the output with the layer aLayer, the OSM type aOsmType, and the current attributes.

commit(string aLayer,string aOsmType,int aObjectType) writes a new map object to the output with the layer aLayer, the OSM type aOsmType, the object type aObjectType, and the current attributes.

copy(string aFieldName) copies a field or fields to map object attributes with the same name. aFieldName may contain the wild cards * and ?.

copy(string aFieldName) copies a field or fields to map object attributes with the same name. aFieldName may contain the wild cards * and ?.

copy(string aPrefix,string aFieldName) copies a field or fields to map object attributes with the same name, prefixed by aPrefix. aFieldName may contain the wild cards * and ?. A common us of this function is to add the prefix '_' (an underscore) to prevent attributes from being searchable as text.

dbf_record_count(string aPrefix) returns the number of records for the current key, in the associated DBF file which was opened using the <dbf> command in the surrounding XML import rules with the prefix aPrefix.

exists(string aFieldName) returns a boolean value that is true if the field aFieldName exists (has a non-empty value) in the current record.

exists(string aFieldName,int aSubscript) returns a boolean value that is true if the field aFieldName, subscripted by aSubscript, exists (has a non-empty value) in the current record. Subscripts are useful when multiple records have been loaded from associated DBF files using the <dbf> command in the XML import language.

filename() returns the name of the current input file, or the empty string if no input filename is known (for example, if importing data from standard input).

in(string aFieldName) returns the value of the field aFieldName in the current record.

in(string aFieldName,int aSubscript) returns the value of the field aFieldName, subscripted by aSubscript, in the current record. Subscripts are useful when multiple records have been loaded from associated DBF files using the <dbf> command in the XML import language.

is_osm_node() returns true if the current record is an OpenStreetMap node.

is_osm_relation() returns true if the current record is an OpenStreetMap relation.

is_osm_way() returns true if the current record is an OpenStreetMap way.

set(string aAttribName,value aValue) sets the map object attribute aAttribName to the value aValue, which can be either an integer or a string.

set_int(unsigned int aValue,unsigned int aMask = 0xFFFFFFFF,unsigned int aShift = 0) sets the integer attribute to aValue, optionally selecting the bits in aMask and shifting the value by aShift before setting it.

set_int_low(unsigned int aValue) sets the low 17 bits of the integer attribute to aValue. The upper 15 bits are usually used for the OSM type. 

set_road(unsigned int aValue,unsigned int aMask = 0xFFFFFFFF,unsigned int aShift = 0) sets the road attribute to value, using the optional mask and shift values. Some shortcuts are available:

set_one_way_forward() sets the one-way forward flag: equivalent to set_road(16,48,0).
set_one_way() is the same as set_one_way_forward.
set_one_way_backward() sets the one_way_backward flag: equivalent to set_road(32,48,0).
set_roundabout() 
sets the roundabout flag: equivalent to set_road(4,4,0).
set_toll() sets the toll flag: equivalent to set_road(2,2,0).
set_level(int aLevel) sets the level (0 = normal, 1 = bridge, -1 = tunnel, etc.): equivalent to set_road(aLevel,0xF000,12).
set_bridge() sets the bridge flag: equivalent to set_road(0x10000,0x10000,0).
set_tunnel() sets the tunnel flag: equivalent to set_road(1,1,0).

set_road_type(string aRoadType) sets the road type (by convention, bits 6...11 of the road attribute) to the predefined value in name, which must be one of Motorway, MotorwayLink, TrunkRoad, TrunkRoadLink, PrimaryRoad, PrimaryRoadLink, SecondaryRoad, SecondaryRoadLink, TertiaryRoad, TertiaryRoadLink, UnclassifiedRoad, ResidentialRoad, Track, ServiceRoad, PedestrianRoad, VehicularFerry, PassengerFerry, Other0 ... Other7.

size() returns the size of the current object, which is the length of the diagonal of its axis-oriented bounding box, in meters.

start_group() and end_group() delimit a group. The start_group() function pushes a new output data object on the stack, copying its values from those of the top of the stack. At the end of the group the top-of-stack object is popped and discarded. Thus the group must contain at least one commit() statement to have any useful effect.

<?xml version="1.0" encoding="UTF-8"?>
<CartoTypeImportRules>
<file name='canqc1___________sg.shp'>
<dbf name='canqc1___________si.dbf' prefix='SI_' key='ID'/>

<script>
<![CDATA[
set("name",in("JNCTID"));
auto n = dbf_record_count("SI_");
for (auto i = 0; i < n; ++i)
{
auto attrib_name = "txt" + to_string(i);
set(attrib_name,in("SI_TXTCONT",i));
}
commit("sign");
]]>
</script>
</file>
</CartoTypeImportRules>