2010-04-09 18:46:56 +00:00
#!/usr/bin/env python
2011-07-07 21:22:02 +00:00
2010-04-09 18:46:56 +00:00
import os
2010-08-26 20:42:50 +00:00
import re
2010-04-09 18:46:56 +00:00
import sys
2011-02-05 03:21:02 +00:00
import optparse
2010-08-20 22:20:45 +00:00
import tempfile
2010-08-26 20:42:50 +00:00
2011-02-05 03:21:02 +00:00
__version__ = ' 0.1.0 '
2010-08-26 21:44:43 +00:00
HAS_LXML = False
2010-08-26 20:42:50 +00:00
try :
import lxml . etree as etree
2010-08-26 21:44:43 +00:00
HAS_LXML = True
2010-08-26 20:42:50 +00:00
except ImportError :
try :
import elementtree . ElementTree as etree
2010-08-26 21:44:43 +00:00
except ImportError :
import xml . etree . ElementTree as etree
2010-04-09 18:46:56 +00:00
2011-02-05 03:21:02 +00:00
def color_text ( color , text ) :
if os . name == ' nt ' :
return text
return " \033 [9 %s m %s \033 [0m " % ( color , text )
2010-08-20 22:20:45 +00:00
def indent ( elem , level = 0 ) :
""" http://infix.se/2007/02/06/gentlemen-indent-your-xml
"""
i = " \n " + level * " "
if len ( elem ) :
if not elem . text or not elem . text . strip ( ) :
elem . text = i + " "
for e in elem :
indent ( e , level + 1 )
if not e . tail or not e . tail . strip ( ) :
e . tail = i + " "
if not e . tail or not e . tail . strip ( ) :
e . tail = i
else :
if level and ( not elem . tail or not elem . tail . strip ( ) ) :
elem . tail = i
2010-04-09 18:46:56 +00:00
def name2expr ( sym ) :
2011-09-15 23:22:55 +00:00
if ' name ' not in sym . attrib : return
2010-04-09 18:46:56 +00:00
name = sym . attrib [ ' name ' ]
2011-02-05 03:21:02 +00:00
if re . match ( ' ^ \ [.* \ ] ' , name ) is None \
and ' [ ' not in name \
and ' ] ' not in name \
and not name . startswith ( " ' " ) \
and not name . endswith ( " ' " ) \
and re . match ( " ^ \' .* \' " , name ) is None :
print >> sys . stderr , " Fixing %s " % name
2011-09-15 23:22:55 +00:00
name = ' [ %s ] ' % name
sym . attrib . pop ( ' name ' )
sym . text = name
2010-08-26 20:42:50 +00:00
def handle_attr_changes ( sym ) :
# http://www.w3schools.com/css/pr_text_text-transform.asp
# http://code.google.com/p/mapnik-utils/issues/detail?id=32&colspec=ID%20Type%20Status%20Priority%20Component%20Owner%20Summary
2011-07-07 21:22:02 +00:00
text_convert = sym . attrib . get ( ' text_convert ' , sym . attrib . get ( ' text_transform ' , sym . attrib . get ( ' text_transform ' ) ) )
if text_convert :
2011-02-02 04:20:53 +00:00
# note: css supports text-transform:capitalize but Mapnik does not (yet)
t_ = { ' tolower ' : ' lowercase ' , ' toupper ' : ' uppercase ' , ' none ' : ' none ' }
2011-07-07 21:22:02 +00:00
new = t_ . get ( text_convert )
2010-08-26 20:42:50 +00:00
if new :
2011-07-07 21:22:02 +00:00
sym . attrib [ ' text-transform ' ] = new
2011-02-02 04:20:53 +00:00
else :
2011-07-07 21:22:02 +00:00
sym . attrib [ ' text-transform ' ] = text_convert
if sym . attrib . get ( ' text_convert ' ) :
sym . attrib . pop ( ' text_convert ' )
if sym . attrib . get ( ' text_transform ' ) :
sym . attrib . pop ( ' text_transform ' )
2011-02-02 04:20:53 +00:00
2011-09-12 20:28:35 +00:00
# http://trac.mapnik.org/ticket/807
justify_alignment = sym . attrib . get ( ' justify_alignment ' , sym . attrib . get ( ' justify-alignment ' ) )
if justify_alignment and justify_alignment == " middle " :
sym . attrib [ ' justify-alignment ' ] = ' center '
2011-02-02 04:20:53 +00:00
minimum_distance = sym . attrib . get ( ' min_distance ' )
if minimum_distance :
2011-07-07 21:22:02 +00:00
sym . attrib [ ' minimum-distance ' ] = minimum_distance
2011-02-02 04:20:53 +00:00
sym . attrib . pop ( ' min_distance ' )
minimum_padding = sym . attrib . get ( ' min_padding ' )
if minimum_padding :
2011-07-07 21:22:02 +00:00
sym . attrib [ ' minimum-padding ' ] = minimum_padding
2011-02-02 04:20:53 +00:00
sym . attrib . pop ( ' min_padding ' )
2010-08-26 20:42:50 +00:00
2011-02-05 03:21:02 +00:00
def fixup_sym_with_image ( sym ) :
2010-04-09 18:46:56 +00:00
if sym . attrib . get ( ' width ' ) :
sym . attrib . pop ( ' width ' )
if sym . attrib . get ( ' height ' ) :
sym . attrib . pop ( ' height ' )
2010-05-07 19:46:05 +00:00
if sym . attrib . get ( ' type ' ) :
sym . attrib . pop ( ' type ' )
2010-04-09 18:46:56 +00:00
def fixup_sym_attributes ( sym ) :
2011-02-05 03:21:02 +00:00
if len ( sym . findall ( ' CssParameter ' ) ) :
# copy, so we don't loose after clear()
attrib = dict ( sym . attrib )
for css in sym . findall ( ' CssParameter ' ) :
key = css . attrib . get ( ' name ' )
value = css . text
attrib [ key ] = value
sym . clear ( ) # remove CssParameter elements
for k , v in attrib . items ( ) : # insert attributes instead
sym . attrib [ k ] = v
2010-06-29 08:59:50 +00:00
2011-02-05 03:21:02 +00:00
def underscore2dash ( elem ) :
for i in elem . attrib . items ( ) :
if ' _ ' in i [ 0 ] :
new = i [ 0 ] . replace ( ' _ ' , ' - ' )
old = i [ 0 ]
elem . attrib [ new ] = i [ 1 ]
elem . attrib . pop ( old )
2011-02-15 18:41:20 +00:00
print >> sys . stderr , " Changing %s to %s " % ( old , new )
2011-02-05 03:21:02 +00:00
def upgrade ( input_xml , output_xml = None , indent_xml = True ) :
if not os . path . exists ( input_xml ) :
sys . stderr . write ( ' input xml " %s " does not exist ' % input_xml )
2010-10-22 00:23:02 +00:00
sys . exit ( 1 )
pre_read = open ( input_xml , ' r ' )
2010-08-26 21:44:43 +00:00
if ' !ENTITY ' in pre_read . read ( ) and not HAS_LXML :
sys . stderr . write ( ' \n Sorry, it appears the xml you are trying to upgrade has entities, which requires lxml (python bindings to libxml2) \n ' )
sys . stderr . write ( ' Install lxml with: " easy_install lxml " or download from http://codespeak.net/lxml/ \n ' )
sys . exit ( 1 )
2011-02-05 03:21:02 +00:00
try :
tree = etree . parse ( input_xml )
except :
print ' Could not parse " %s " invalid XML ' % input_xml
return
2010-08-26 21:44:43 +00:00
if hasattr ( tree , ' xinclude ' ) :
2010-08-26 20:45:08 +00:00
tree . xinclude ( )
2010-04-09 18:46:56 +00:00
root = tree . getroot ( )
2011-02-05 03:21:02 +00:00
2010-07-19 12:01:34 +00:00
# rename 'bgcolor' to 'background-color'
if root . attrib . get ( ' bgcolor ' ) :
root . attrib [ ' background-color ' ] = root . attrib . get ( ' bgcolor ' )
root . attrib . pop ( ' bgcolor ' )
2011-02-05 03:21:02 +00:00
# underscores to spaces for <Map ..>
underscore2dash ( root )
2011-03-15 22:49:08 +00:00
root . set ( ' minimum-version ' , ' 0.7.2 ' )
2011-02-05 03:21:02 +00:00
# underscores to spaces for <FontSet ..>
2011-02-09 23:36:09 +00:00
fontset = root . findall ( ' FontSet ' ) or root . findall ( ' */FontSet ' )
2011-02-05 03:21:02 +00:00
for f in fontset :
font = f . findall ( ' Font ' )
for f_ in font :
underscore2dash ( f_ )
# underscores to spaces for <Layer ..>
2011-02-09 23:36:09 +00:00
layers = root . findall ( ' Layer ' ) or root . findall ( ' */Layer ' )
2011-02-05 03:21:02 +00:00
for l in layers :
underscore2dash ( l )
2010-11-08 19:12:29 +00:00
2011-02-09 23:36:09 +00:00
styles = root . findall ( ' Style ' ) or root . findall ( ' */Style ' )
2010-08-26 20:42:50 +00:00
if not len ( styles ) :
2010-08-20 22:20:45 +00:00
sys . stderr . write ( ' ### Warning, no styles encountered and nothing able to be upgraded! \n ' )
2010-08-26 20:42:50 +00:00
else :
for style in styles :
for rule in style . findall ( ' Rule ' ) :
for sym in rule . findall ( ' TextSymbolizer ' ) or [ ] :
name2expr ( sym )
2010-09-18 19:33:13 +00:00
handle_attr_changes ( sym )
2011-02-05 03:21:02 +00:00
fixup_sym_attributes ( sym )
underscore2dash ( sym )
2010-08-26 20:42:50 +00:00
for sym in rule . findall ( ' ShieldSymbolizer ' ) or [ ] :
name2expr ( sym )
2011-02-02 04:20:53 +00:00
handle_attr_changes ( sym )
2011-02-05 03:21:02 +00:00
fixup_sym_attributes ( sym )
underscore2dash ( sym )
fixup_sym_with_image ( sym )
2010-08-26 20:42:50 +00:00
for sym in rule . findall ( ' PointSymbolizer ' ) or [ ] :
2011-02-05 03:21:02 +00:00
fixup_sym_with_image ( sym )
fixup_sym_attributes ( sym )
underscore2dash ( sym )
for sym in rule . findall ( ' PolygonPatternSymbolizer ' ) or [ ] :
fixup_sym_with_image ( sym )
fixup_sym_attributes ( sym )
underscore2dash ( sym )
for sym in rule . findall ( ' LinePatternSymbolizer ' ) or [ ] :
fixup_sym_with_image ( sym )
fixup_sym_attributes ( sym )
underscore2dash ( sym )
2010-08-26 20:42:50 +00:00
for sym in rule . findall ( ' LineSymbolizer ' ) or [ ] :
fixup_sym_attributes ( sym )
2011-02-05 03:21:02 +00:00
underscore2dash ( sym )
2010-08-26 20:42:50 +00:00
for sym in rule . findall ( ' PolygonSymbolizer ' ) or [ ] :
fixup_sym_attributes ( sym )
2011-02-05 03:21:02 +00:00
underscore2dash ( sym )
2010-08-26 20:42:50 +00:00
for sym in rule . findall ( ' RasterSymbolizer ' ) or [ ] :
fixup_sym_attributes ( sym )
2011-02-05 03:21:02 +00:00
underscore2dash ( sym )
2010-08-26 20:42:50 +00:00
for sym in rule . findall ( ' BuildingSymbolizer ' ) or [ ] :
fixup_sym_attributes ( sym )
2011-02-05 03:21:02 +00:00
underscore2dash ( sym )
for sym in rule . findall ( ' GlyphSymbolizer ' ) or [ ] :
fixup_sym_attributes ( sym )
underscore2dash ( sym )
2011-02-15 18:41:20 +00:00
for sym in rule . findall ( ' MarkersSymbolizer ' ) or [ ] :
fixup_sym_attributes ( sym )
underscore2dash ( sym )
2011-02-05 03:21:02 +00:00
if indent_xml :
indent ( root )
if output_xml :
tree . write ( output_xml )
else :
tree . write ( input_xml )
parser = optparse . OptionParser ( usage = """ % prog <input xml> [options]
Upgrade a Mapnik XML stylesheet to Mapnik 2.0
Full help :
$ % prog - h ( or - - help for possible options )
Read ' map.xml ' and write new ' map2.xml '
$ % prog map . xml map2 . xml
Update ' map.xml ' in place ( * Careful * )
$ % prog map . xml - - in - place
""" , version= ' % prog ' + __version__)
parser . add_option ( ' --indent ' ,
dest = ' indent_xml ' ,
action = ' store_true ' ,
default = False ,
help = ' Indent the resulting XML ' )
2010-06-29 08:59:50 +00:00
2011-02-05 03:21:02 +00:00
parser . add_option ( ' --in-place ' ,
dest = ' update_in_place ' ,
action = ' store_true ' ,
default = False ,
help = ' Update and overwrite the map in place ' )
if __name__ == " __main__ " :
( options , args ) = parser . parse_args ( )
if not len ( args ) > 0 :
parser . error ( " Please provide the path to a map.xml and a new xml to write " )
input_xml = args [ 0 ]
output_xml = None
if len ( args ) < 3 and not options . update_in_place :
if len ( args ) == 2 :
output_xml = args [ 1 ]
if ( len ( args ) == 1 ) or ( input_xml == output_xml ) :
parser . error ( color_text ( 1 , ' \n \n Are you sure you want to overwrite " %s " ? \n If so, then pass --in-place to confirm. \n Otherwise pass a different filename to write an upgraded copy to. \n ' % input_xml ) )
print ' Upgrading " %s " to " %s " ... ' % ( input_xml , output_xml )
upgrade ( input_xml , output_xml = output_xml , indent_xml = options . indent_xml )
elif len ( args ) == 1 :
2011-09-12 20:28:35 +00:00
print ' Upgrading " %s " ... ' % ( input_xml )
2011-02-05 03:21:02 +00:00
upgrade ( input_xml , output_xml = output_xml , indent_xml = options . indent_xml )
elif len ( args ) > 1 : # assume a list of inputs
found = [ ]
for input_xml in args :
if os . path . exists ( input_xml ) and input_xml not in found :
print ' Upgrading " %s " in place... ' % input_xml
found . append ( input_xml )
upgrade ( input_xml , output_xml = None , indent_xml = options . indent_xml )