Skip to content

Instantly share code, notes, and snippets.

@BertrandBordage
Last active May 31, 2018 16:43
Show Gist options
  • Star 1 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save BertrandBordage/1cab3746ad81feddf2da9132551da2f4 to your computer and use it in GitHub Desktop.
Save BertrandBordage/1cab3746ad81feddf2da9132551da2f4 to your computer and use it in GitHub Desktop.
Clean SVG
#!/usr/bin/env python
from argparse import ArgumentParser
from io import BytesIO
import re
from xml.etree import ElementTree
NAMESPACED_RE = re.compile(r'^\{(.+)\}.+$')
SVG_NAMESPACE = 'http://www.w3.org/2000/svg'
ALLOWED_NAMESPACES = {
SVG_NAMESPACE: '',
'http://www.w3.org/1999/xlink': 'xlink',
}
GROUP_TAG = '{%s}g' % SVG_NAMESPACE
def remove_useless_ids(root):
all_elements = root.findall('.//')
all_elements.append(root)
elements_with_id = root.findall('.//*[@id]')
elements_with_id.append(root)
for element_with_id in elements_with_id:
try:
id_reference = '#' + element_with_id.attrib['id']
except KeyError:
continue
for element in all_elements:
if any(id_reference in value
for value in element.attrib.values()):
break
else:
del element_with_id.attrib['id']
class UselessTag(Exception):
pass
def clean_element(element, allowed_namespaces):
match = NAMESPACED_RE.match(element.tag)
if match is not None and match.group(1) not in allowed_namespaces:
raise UselessTag
for i, child in enumerate(tuple(element)):
try:
clean_element(child, allowed_namespaces)
if child.tag == GROUP_TAG:
if len(child) == 0:
raise UselessTag
if len(child) == 1 and not child.attrib:
element.insert(i, tuple(child)[0])
raise UselessTag
except UselessTag:
element.remove(child)
for k in tuple(element.attrib):
match = NAMESPACED_RE.match(k)
if match is not None and match.group(1) not in allowed_namespaces:
del element.attrib[k]
def clean_svg(input_path, output_path=None,
allowed_namespaces=ALLOWED_NAMESPACES):
for allowed_namespace, prefix in allowed_namespaces.items():
ElementTree.register_namespace(prefix, allowed_namespace)
tree = ElementTree.parse(input_path)
root = tree.getroot()
clean_element(root, allowed_namespaces)
remove_useless_ids(root)
if output_path is None:
with BytesIO() as temporary_file:
tree.write(temporary_file, encoding='utf-8')
return temporary_file.getvalue().decode()
tree.write(output_path, encoding='utf-8')
return 'Result saved in %s' % output_path
if __name__ == '__main__':
parser = ArgumentParser(
description='Cleans a SVG from useless tags and attributes.')
parser.add_argument('input_path', type=str)
parser.add_argument('output_path', type=str, nargs='?')
print(clean_svg(**vars(parser.parse_args())))
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment