Skip to content

Commit 9308164

Browse files
kovidgoyalgsnedders
authored andcommitted
Preserve attribute order when parsing
1 parent 71d7774 commit 9308164

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
@@ -437,6 +437,73 @@
437437
(namespaces["mathml"], "mtext")
438438
])
439439

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

275277
if token["type"] == tokenTypes["StartTag"]:
276-
token["data"] = dict(token["data"][::-1])
278+
token["data"] = OrderedDict(token['data'])
277279

278280
return token
279281

280282
def adjustMathMLAttributes(self, token):
281-
replacements = {"definitionurl": "definitionURL"}
282-
for k, v in replacements.items():
283-
if k in token["data"]:
284-
token["data"][v] = token["data"][k]
285-
del token["data"][k]
283+
adjust_attributes(token, adjustMathMLAttributes)
286284

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

358288
def adjustForeignAttributes(self, token):
359-
replacements = adjustForeignAttributesMap
360-
361-
for originalName in token["data"].keys():
362-
if originalName in replacements:
363-
foreignName = replacements[originalName]
364-
token["data"][foreignName] = token["data"][originalName]
365-
del token["data"][originalName]
289+
adjust_attributes(token, adjustForeignAttributesMap)
366290

367291
def reparseTokenNormal(self, token):
368292
# pylint:disable=unused-argument
@@ -2791,6 +2715,12 @@ def processEndTag(self, token):
27912715
}
27922716

27932717

2718+
def adjust_attributes(token, replacements):
2719+
if frozenset(token['data']) & frozenset(replacements):
2720+
token['data'] = OrderedDict(
2721+
(replacements.get(k, k), v) for k, v in token['data'].iteritems())
2722+
2723+
27942724
def impliedTagToken(name, type="EndTag", attributes=None,
27952725
selfClosing=False):
27962726
if attributes is None:

0 commit comments

Comments
 (0)