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 aFeatureType) writes a new map object to the output with the layer aLayer, the feature type aFeatureType, and the current attributes.

commit(string aLayer,stringaFeatureType,int aObjectType) writes a new map object to the output with the layer aLayer, the feature type aFeatureType, 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_feature_type(string aName) sets the feature type (route or non-route type) to aName. Names are either full words or phrases like 'trunk road', used for route types, or three-letter abbreviations like 'stn' meaning a railway station. Letter case and spaces are ignored when comparing names: 'Motorway' is the same as 'motorway'. Route 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.

set_sub_type(unsigned int aValue) sets the sub-type of a non-route object to a value in the range 0...2047.

set_speed_limit(unsigned int aValue) sets the speed limit of a route object to a value in the range 0...255.

set_osm_speed_limit(string aTag) sets the speed limit  of a route object by interpreting the value of the OpenStreetMap tag named by aTag, which is in the OpenStreetMap format for a speed limit. The tag is normally 'maxspeed'. 

set_one_way_forward() sets the one-way forward flag.
set_one_way() is the same as set_one_way_forward.
set_one_way_backward() sets the one_way_backward flag,
set_two_way() sets the road to two-way.
set_roundabout() 
sets the roundabout flag.
set_toll() sets the toll flag.
set_level(int aLevel) sets the level (0 = normal, 1 = bridge, -1 = tunnel, etc.).
set_bridge() sets the bridge flag.
set_tunnel() sets the tunnel flag.

set_public_access(bool aValue) sets or removes public access.
set_pedestrian_access(bool aValue) sets or removes pedestrian access.
set_cycle_access(bool aValue) sets or removes cycle access.
set_motor_vehicle_access(bool aValue) sets or removes motor vehicle access.
set_vehicle_access(bool aValue) sets or removes vehicle access.
set_emergency_access(bool aValue) sets or removes emergency vehicle access.
set_pedestrian_access(bool aValue) sets or removes pedestrian access.
set_other_access_restricted(bool aValue) sets or clears the flag indicating that there are other access restrictions stored in string attributes of the map object.

set_feature_info_raw_value(unsigned int aValue) sets the raw integer value of the feature info.

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>