serializeXML: Refactor the attribute ordering code
Rewrite the code for ordering attributes in the output and extract it into a function. As a side-effect, we ensure we only use the `.item(index)` method once per attribute because it is inefficient (see https://bugs.python.org/issue40689). Signed-off-by: Niels Thykier <niels@thykier.net>
This commit is contained in:
parent
5be6b03d7c
commit
9656569a72
1 changed files with 38 additions and 24 deletions
|
|
@ -3433,6 +3433,42 @@ TEXT_CONTENT_ELEMENTS = ['text', 'tspan', 'tref', 'textPath', 'altGlyph',
|
||||||
'flowDiv', 'flowPara', 'flowSpan', 'flowTref', 'flowLine']
|
'flowDiv', 'flowPara', 'flowSpan', 'flowTref', 'flowLine']
|
||||||
|
|
||||||
|
|
||||||
|
KNOWN_ATTRS = [
|
||||||
|
# TODO: Maybe update with full list from https://www.w3.org/TR/SVG/attindex.html
|
||||||
|
# (but should be kept intuitively ordered)
|
||||||
|
'id', 'xml:id', 'class',
|
||||||
|
'transform',
|
||||||
|
'x', 'y', 'z', 'width', 'height', 'x1', 'x2', 'y1', 'y2',
|
||||||
|
'dx', 'dy', 'rotate', 'startOffset', 'method', 'spacing',
|
||||||
|
'cx', 'cy', 'r', 'rx', 'ry', 'fx', 'fy',
|
||||||
|
'd', 'points',
|
||||||
|
] + sorted(svgAttributes) + [
|
||||||
|
'style',
|
||||||
|
]
|
||||||
|
|
||||||
|
KNOWN_ATTRS_ORDER_BY_NAME = defaultdict(lambda: len(KNOWN_ATTRS),
|
||||||
|
{name: order for order, name in enumerate(KNOWN_ATTRS)})
|
||||||
|
|
||||||
|
|
||||||
|
# use custom order for known attributes and alphabetical order for the rest
|
||||||
|
def _attribute_sort_key_function(attribute):
|
||||||
|
name = attribute.name
|
||||||
|
order_value = KNOWN_ATTRS_ORDER_BY_NAME[name]
|
||||||
|
return order_value, name
|
||||||
|
|
||||||
|
|
||||||
|
def attributes_ordered_for_output(element):
|
||||||
|
if not element.hasAttributes():
|
||||||
|
return []
|
||||||
|
attribute = element.attributes
|
||||||
|
# The .item(i) call is painfully slow (bpo#40689). Therefore we ensure we
|
||||||
|
# call it at most once per attribute.
|
||||||
|
# - it would be many times faster to use `attribute.values()` but sadly
|
||||||
|
# that is an "experimental" interface.
|
||||||
|
return sorted((attribute.item(i) for i in range(attribute.length)),
|
||||||
|
key=_attribute_sort_key_function)
|
||||||
|
|
||||||
|
|
||||||
# hand-rolled serialization function that has the following benefits:
|
# hand-rolled serialization function that has the following benefits:
|
||||||
# - pretty printing
|
# - pretty printing
|
||||||
# - somewhat judicious use of whitespace
|
# - somewhat judicious use of whitespace
|
||||||
|
|
@ -3453,30 +3489,8 @@ def serializeXML(element, options, indent_depth=0, preserveWhitespace=False):
|
||||||
outParts.extend([(indent_type * indent_depth), '<', element.nodeName])
|
outParts.extend([(indent_type * indent_depth), '<', element.nodeName])
|
||||||
|
|
||||||
# now serialize the other attributes
|
# now serialize the other attributes
|
||||||
known_attr = [
|
attrs = attributes_ordered_for_output(element)
|
||||||
# TODO: Maybe update with full list from https://www.w3.org/TR/SVG/attindex.html
|
for attr in attrs:
|
||||||
# (but should be kept inuitively ordered)
|
|
||||||
'id', 'xml:id', 'class',
|
|
||||||
'transform',
|
|
||||||
'x', 'y', 'z', 'width', 'height', 'x1', 'x2', 'y1', 'y2',
|
|
||||||
'dx', 'dy', 'rotate', 'startOffset', 'method', 'spacing',
|
|
||||||
'cx', 'cy', 'r', 'rx', 'ry', 'fx', 'fy',
|
|
||||||
'd', 'points',
|
|
||||||
] + sorted(svgAttributes) + [
|
|
||||||
'style',
|
|
||||||
]
|
|
||||||
attrList = element.attributes
|
|
||||||
attrName2Index = dict([(attrList.item(i).nodeName, i) for i in range(attrList.length)])
|
|
||||||
# use custom order for known attributes and alphabetical order for the rest
|
|
||||||
attrIndices = []
|
|
||||||
for name in known_attr:
|
|
||||||
if name in attrName2Index:
|
|
||||||
attrIndices.append(attrName2Index[name])
|
|
||||||
del attrName2Index[name]
|
|
||||||
attrIndices += [attrName2Index[name] for name in sorted(attrName2Index)]
|
|
||||||
for index in attrIndices:
|
|
||||||
attr = attrList.item(index)
|
|
||||||
|
|
||||||
attrValue = attr.nodeValue
|
attrValue = attr.nodeValue
|
||||||
quote, xml_ent = choose_quote_character(attrValue)
|
quote, xml_ent = choose_quote_character(attrValue)
|
||||||
attrValue = make_well_formed(attrValue, xml_ent)
|
attrValue = make_well_formed(attrValue, xml_ent)
|
||||||
|
|
|
||||||
Loading…
Add table
Add a link
Reference in a new issue