Skip to content

Commit 8c2d68a

Browse files
kovidgoyalgsnedders
authored andcommitted
Preserve attribute order when parsing
1 parent cd4f239 commit 8c2d68a

File tree

2 files changed

+79
-82
lines changed

2 files changed

+79
-82
lines changed

html5lib/constants.py

Lines changed: 67 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -431,6 +431,73 @@
431431
(namespaces["mathml"], "mtext")
432432
])
433433

434+
adjustSVGAttributes = {
435+
"attributename": "attributeName",
436+
"attributetype": "attributeType",
437+
"basefrequency": "baseFrequency",
438+
"baseprofile": "baseProfile",
439+
"calcmode": "calcMode",
440+
"clippathunits": "clipPathUnits",
441+
"contentscripttype": "contentScriptType",
442+
"contentstyletype": "contentStyleType",
443+
"diffuseconstant": "diffuseConstant",
444+
"edgemode": "edgeMode",
445+
"externalresourcesrequired": "externalResourcesRequired",
446+
"filterres": "filterRes",
447+
"filterunits": "filterUnits",
448+
"glyphref": "glyphRef",
449+
"gradienttransform": "gradientTransform",
450+
"gradientunits": "gradientUnits",
451+
"kernelmatrix": "kernelMatrix",
452+
"kernelunitlength": "kernelUnitLength",
453+
"keypoints": "keyPoints",
454+
"keysplines": "keySplines",
455+
"keytimes": "keyTimes",
456+
"lengthadjust": "lengthAdjust",
457+
"limitingconeangle": "limitingConeAngle",
458+
"markerheight": "markerHeight",
459+
"markerunits": "markerUnits",
460+
"markerwidth": "markerWidth",
461+
"maskcontentunits": "maskContentUnits",
462+
"maskunits": "maskUnits",
463+
"numoctaves": "numOctaves",
464+
"pathlength": "pathLength",
465+
"patterncontentunits": "patternContentUnits",
466+
"patterntransform": "patternTransform",
467+
"patternunits": "patternUnits",
468+
"pointsatx": "pointsAtX",
469+
"pointsaty": "pointsAtY",
470+
"pointsatz": "pointsAtZ",
471+
"preservealpha": "preserveAlpha",
472+
"preserveaspectratio": "preserveAspectRatio",
473+
"primitiveunits": "primitiveUnits",
474+
"refx": "refX",
475+
"refy": "refY",
476+
"repeatcount": "repeatCount",
477+
"repeatdur": "repeatDur",
478+
"requiredextensions": "requiredExtensions",
479+
"requiredfeatures": "requiredFeatures",
480+
"specularconstant": "specularConstant",
481+
"specularexponent": "specularExponent",
482+
"spreadmethod": "spreadMethod",
483+
"startoffset": "startOffset",
484+
"stddeviation": "stdDeviation",
485+
"stitchtiles": "stitchTiles",
486+
"surfacescale": "surfaceScale",
487+
"systemlanguage": "systemLanguage",
488+
"tablevalues": "tableValues",
489+
"targetx": "targetX",
490+
"targety": "targetY",
491+
"textlength": "textLength",
492+
"viewbox": "viewBox",
493+
"viewtarget": "viewTarget",
494+
"xchannelselector": "xChannelSelector",
495+
"ychannelselector": "yChannelSelector",
496+
"zoomandpan": "zoomAndPan"
497+
}
498+
499+
adjustMathMLAttributes = {"definitionurl": "definitionURL"}
500+
434501
adjustForeignAttributes = {
435502
"xlink:actuate": ("xlink", "actuate", namespaces["xlink"]),
436503
"xlink:arcrole": ("xlink", "arcrole", namespaces["xlink"]),

html5lib/html5parser.py

Lines changed: 12 additions & 82 deletions
Original file line numberDiff line numberDiff line change
@@ -2,6 +2,7 @@
22
from six import with_metaclass
33

44
import types
5+
from collections import OrderedDict
56

67
from . import inputstream
78
from . import tokenizer
@@ -17,6 +18,7 @@
1718
namespaces,
1819
htmlIntegrationPointElements, mathmlTextIntegrationPointElements,
1920
adjustForeignAttributes as adjustForeignAttributesMap,
21+
adjustMathMLAttributes, adjustSVGAttributes,
2022
E,
2123
ReparseException
2224
)
@@ -263,96 +265,18 @@ def normalizeToken(self, token):
263265
""" HTML5 specific normalizations to the token stream """
264266

265267
if token["type"] == tokenTypes["StartTag"]:
266-
token["data"] = dict(token["data"][::-1])
268+
token["data"] = OrderedDict(token['data'])
267269

268270
return token
269271

270272
def adjustMathMLAttributes(self, token):
271-
replacements = {"definitionurl": "definitionURL"}
272-
for k, v in replacements.items():
273-
if k in token["data"]:
274-
token["data"][v] = token["data"][k]
275-
del token["data"][k]
273+
adjust_attributes(token, adjustMathMLAttributes)
276274

277275
def adjustSVGAttributes(self, token):
278-
replacements = {
279-
"attributename": "attributeName",
280-
"attributetype": "attributeType",
281-
"basefrequency": "baseFrequency",
282-
"baseprofile": "baseProfile",
283-
"calcmode": "calcMode",
284-
"clippathunits": "clipPathUnits",
285-
"contentscripttype": "contentScriptType",
286-
"contentstyletype": "contentStyleType",
287-
"diffuseconstant": "diffuseConstant",
288-
"edgemode": "edgeMode",
289-
"externalresourcesrequired": "externalResourcesRequired",
290-
"filterres": "filterRes",
291-
"filterunits": "filterUnits",
292-
"glyphref": "glyphRef",
293-
"gradienttransform": "gradientTransform",
294-
"gradientunits": "gradientUnits",
295-
"kernelmatrix": "kernelMatrix",
296-
"kernelunitlength": "kernelUnitLength",
297-
"keypoints": "keyPoints",
298-
"keysplines": "keySplines",
299-
"keytimes": "keyTimes",
300-
"lengthadjust": "lengthAdjust",
301-
"limitingconeangle": "limitingConeAngle",
302-
"markerheight": "markerHeight",
303-
"markerunits": "markerUnits",
304-
"markerwidth": "markerWidth",
305-
"maskcontentunits": "maskContentUnits",
306-
"maskunits": "maskUnits",
307-
"numoctaves": "numOctaves",
308-
"pathlength": "pathLength",
309-
"patterncontentunits": "patternContentUnits",
310-
"patterntransform": "patternTransform",
311-
"patternunits": "patternUnits",
312-
"pointsatx": "pointsAtX",
313-
"pointsaty": "pointsAtY",
314-
"pointsatz": "pointsAtZ",
315-
"preservealpha": "preserveAlpha",
316-
"preserveaspectratio": "preserveAspectRatio",
317-
"primitiveunits": "primitiveUnits",
318-
"refx": "refX",
319-
"refy": "refY",
320-
"repeatcount": "repeatCount",
321-
"repeatdur": "repeatDur",
322-
"requiredextensions": "requiredExtensions",
323-
"requiredfeatures": "requiredFeatures",
324-
"specularconstant": "specularConstant",
325-
"specularexponent": "specularExponent",
326-
"spreadmethod": "spreadMethod",
327-
"startoffset": "startOffset",
328-
"stddeviation": "stdDeviation",
329-
"stitchtiles": "stitchTiles",
330-
"surfacescale": "surfaceScale",
331-
"systemlanguage": "systemLanguage",
332-
"tablevalues": "tableValues",
333-
"targetx": "targetX",
334-
"targety": "targetY",
335-
"textlength": "textLength",
336-
"viewbox": "viewBox",
337-
"viewtarget": "viewTarget",
338-
"xchannelselector": "xChannelSelector",
339-
"ychannelselector": "yChannelSelector",
340-
"zoomandpan": "zoomAndPan"
341-
}
342-
for originalName in list(token["data"].keys()):
343-
if originalName in replacements:
344-
svgName = replacements[originalName]
345-
token["data"][svgName] = token["data"][originalName]
346-
del token["data"][originalName]
276+
adjust_attributes(token, adjustSVGAttributes)
347277

348278
def adjustForeignAttributes(self, token):
349-
replacements = adjustForeignAttributesMap
350-
351-
for originalName in token["data"].keys():
352-
if originalName in replacements:
353-
foreignName = replacements[originalName]
354-
token["data"][foreignName] = token["data"][originalName]
355-
del token["data"][originalName]
279+
adjust_attributes(token, adjustForeignAttributesMap)
356280

357281
def reparseTokenNormal(self, token):
358282
self.parser.phase()
@@ -2702,6 +2626,12 @@ def processEndTag(self, token):
27022626
}
27032627

27042628

2629+
def adjust_attributes(token, replacements):
2630+
if frozenset(token['data']) & frozenset(replacements):
2631+
token['data'] = OrderedDict(
2632+
(replacements.get(k, k), v) for k, v in token['data'].iteritems())
2633+
2634+
27052635
def impliedTagToken(name, type="EndTag", attributes=None,
27062636
selfClosing=False):
27072637
if attributes is None:

0 commit comments

Comments
 (0)