If the styling of elements is thematic (and you know what columns drive the theme) you can build a QML file programmatically in PostgreSQL.
For example, I have a file with ~150 styles for government zone polygons (subsets of the zones have the same style). The data was originally in MapInfo format in two TAB files - one with the zone polygons, another with aspatial data like zone_code, description, group, and lastly 'red', 'green' 'blue' (the last 3 are the RGB values for the recommended colour ramp).
To create my QML file, I did the following:
(1) import the data into PostgreSQL (using ogr2ogr);
(2) write a python script that looks like this -
# Set up connection to database
conn_string = "host='localhost' dbname='[db]' user='[me]' password='[not telling]'"
# Connect to database
conn = psycopg2.connect(conn_string)
# set up default cursor (to run queries)
cursor = conn.cursor()
# Get LGA details; store them to a list
xmlattributes(\'2.8.2-Wien\' as version),
xmlattributes(\'zone_code\' as attr, 0 as symbollevels, \'categorizedSymbol\' as type),
xmlattributes(1 as alpha, \'fill\' as type, gid-1 as name),
xmlattributes(0 as pass, \'SimpleFill\' as class, 0 as locked),
xmlattributes(\'color\' as k, rgba as v)),
xmlattributes(\'outline_color\' as k, \'230,230,230,255\' as v)))))),
xmlattributes(\'true\' as render, gid-1 as symbol, zone_code as value, zone_code||\' (\'|| description || \')\' as label))))))
xml_new = ''
for row in cursor:
xml_new = row
#print 'XML_New: ', xml_new # testing only
# pre-pend QGIS-specific DOCYTPE to XML
outStr= "<!DOCTYPE qgis PUBLIC 'http://mrcc.com/qgis.dtd' 'SYSTEM'>\n" + xml_new
# open destination XML file and save XML to it
outFile = open("Zones.qml", 'w')
The script is kludgy (there's no need for the
for row in cursor since
cursor only returns one row), but result is exactly what I wanted: a QML file that I could distribute to my colleagues so that they could style Zoned data with 3 clicks. (Bonus benefit: when theme files need to be built for different sets of categories, only the query has to change: we have ~25 different theme sets, and they were all constructed from that one script by changing the query and the destination file).
The output looks like this -
<!DOCTYPE qgis PUBLIC 'http://mrcc.com/qgis.dtd' 'SYSTEM' >
<renderer-v2 attr="zone_code" symbollevels="0" type="categorizedSymbol">
<symbol alpha="1" type="fill" name="0">
<layer pass="0" class="SimpleFill" locked="0">
<prop k="color" v="240,217,250,255" />
<prop k="outline_color" v="230,230,230,255" />
<category render="true" symbol="0" value="B1Z" label="B1Z (Commercial 1 Zone)" />
For your specific theme you would have to write the appropriate query (which means you need to know the columns that 'drive' the style categories).
MapInfo stupidly stores styling data row-by-row (the 90s called, they want their 'style and content mixed' back), but it can be retrieved if you add the a -SQL statement to your ogr2ogr import statement adding OGR_STYLE to the retrieved set. You can then parse the 'style' column in PostgreSQL to get the styling information out.
This is the script that I use to import all TAB files in a given directory (the slashes are just to show that it's one line, broken up for clarity): the relevant additional bit is the -SQL line.
for %f in (*.tab) do
ogr2ogr -nlt GEOMETRY \
-lco GEOMETRY_NAME=g1 \
-lco SCHEMA=test \
-lco FID=id1 \
-lco OVERWRITE=YES \
-f "PostgreSQL" \
--config OGR_TRUNCATE YES \
-a_srs EPSG:4283 \
-SQL "select *, CAST (OGR_STYLE AS Character (255)) AS style from %~nf" \
PG:"host=localhost user=[me] dbname=[db] password=[not telling]" \
If you then look at the imported data, you will find a column 'style' that has entries that look like
For point data it will look different, of course - it'll probably have marker types and what-not.
In all likelihood, someone with a better knowledge of how style information is stored in "the Windows 8 of GIS" (MapInfo) would be able to tell you how to get the specific colour and symbol information more directly in the -SQL statement (I've been meaning to find out, but I try to think about MapInfo as little as possible: I find it easy enough to automatically parse the 'style' column in PostgreSQL with a script).