Skip to content

Commit a30eb28

Browse files
committed
fixup! Fix #11, #12: quote attributes that need escaping in legacy browsers
1 parent c923491 commit a30eb28

File tree

3 files changed

+128
-2
lines changed

3 files changed

+128
-2
lines changed

html5lib/serializer/htmlserializer.py

+5-2
Original file line numberDiff line numberDiff line change
@@ -248,11 +248,14 @@ def serialize(self, treewalker, encoding=None):
248248
(k not in booleanAttributes.get(name, tuple()) and
249249
k not in booleanAttributes.get("", tuple())):
250250
yield self.encodeStrict("=")
251-
if self.quote_attr_values == "always" or len(v) == 0:
251+
if (self.quote_attr_values == "always" or
252+
self.quote_attr_values is True or
253+
len(v) == 0):
252254
quote_attr = True
253255
elif self.quote_attr_values == "spec":
254256
quote_attr = quoteAttributeSpec.search(v) is not None
255-
elif self.quote_attr_values == "legacy":
257+
elif (self.quote_attr_values == "legacy" or
258+
self.quote_attr_values is False):
256259
quote_attr = quoteAttributeLegacy.search(v) is not None
257260
else:
258261
raise ValueError("quote_attr_values must be one of: "

html5lib/tests/serializer-testdata/options.test

+92
Original file line numberDiff line numberDiff line change
@@ -69,6 +69,98 @@
6969
"quote_attr_values": true
7070
}
7171
},
72+
{
73+
"expected": [
74+
"<div class=\"foo\">"
75+
],
76+
"input": [
77+
[
78+
"StartTag",
79+
"http://www.w3.org/1999/xhtml",
80+
"div",
81+
[
82+
{
83+
"namespace": null,
84+
"name": "class",
85+
"value": "foo"
86+
}
87+
]
88+
]
89+
],
90+
"description": "non-minimized quote_attr_values=true",
91+
"options": {
92+
"quote_attr_values": true
93+
}
94+
},
95+
{
96+
"expected": [
97+
"<div class=\"foo\">"
98+
],
99+
"input": [
100+
[
101+
"StartTag",
102+
"http://www.w3.org/1999/xhtml",
103+
"div",
104+
[
105+
{
106+
"namespace": null,
107+
"name": "class",
108+
"value": "foo"
109+
}
110+
]
111+
]
112+
],
113+
"description": "non-minimized quote_attr_values='always'",
114+
"options": {
115+
"quote_attr_values": "always"
116+
}
117+
},
118+
{
119+
"expected": [
120+
"<div class=foo>"
121+
],
122+
"input": [
123+
[
124+
"StartTag",
125+
"http://www.w3.org/1999/xhtml",
126+
"div",
127+
[
128+
{
129+
"namespace": null,
130+
"name": "class",
131+
"value": "foo"
132+
}
133+
]
134+
]
135+
],
136+
"description": "non-minimized quote_attr_values='legacy'",
137+
"options": {
138+
"quote_attr_values": "legacy"
139+
}
140+
},
141+
{
142+
"expected": [
143+
"<div class=foo>"
144+
],
145+
"input": [
146+
[
147+
"StartTag",
148+
"http://www.w3.org/1999/xhtml",
149+
"div",
150+
[
151+
{
152+
"namespace": null,
153+
"name": "class",
154+
"value": "foo"
155+
}
156+
]
157+
]
158+
],
159+
"description": "non-minimized quote_attr_values='spec'",
160+
"options": {
161+
"quote_attr_values": "spec"
162+
}
163+
},
72164
{
73165
"expected": [
74166
"<img />"

html5lib/tests/test_serializer.py

+31
Original file line numberDiff line numberDiff line change
@@ -146,6 +146,37 @@ def testComment():
146146
throwsWithLatin1([["Comment", "\u0101"]])
147147

148148

149+
@pytest.mark.parametrize("c", list("\t\n\u000C\x20\r\"'=<>`"))
150+
def testSpecQuoteAttribute(c):
151+
input_ = [["StartTag", "http://www.w3.org/1999/xhtml", "span",
152+
[{"namespace": None, "name": "foo", "value": c}]]]
153+
if c == '"':
154+
output_ = ["<span foo='%s'>" % c]
155+
else:
156+
output_ = ['<span foo="%s">' % c]
157+
options_ = {"quote_attr_values": "spec"}
158+
runSerializerTest(input_, output_, options_)
159+
160+
161+
@pytest.mark.parametrize("c", list("\t\n\u000C\x20\r\"'=<>`"
162+
"\x00\x01\x02\x03\x04\x05\x06\x07\x08\t\n"
163+
"\x0b\x0c\r\x0e\x0f\x10\x11\x12\x13\x14\x15"
164+
"\x16\x17\x18\x19\x1a\x1b\x1c\x1d\x1e\x1f"
165+
"\x20\x2f\x60\xa0\u1680\u180e\u180f\u2000"
166+
"\u2001\u2002\u2003\u2004\u2005\u2006\u2007"
167+
"\u2008\u2009\u200a\u2028\u2029\u202f\u205f"
168+
"\u3000"))
169+
def testLegacyQuoteAttribute(c):
170+
input_ = [["StartTag", "http://www.w3.org/1999/xhtml", "span",
171+
[{"namespace": None, "name": "foo", "value": c}]]]
172+
if c == '"':
173+
output_ = ["<span foo='%s'>" % c]
174+
else:
175+
output_ = ['<span foo="%s">' % c]
176+
options_ = {"quote_attr_values": "legacy"}
177+
runSerializerTest(input_, output_, options_)
178+
179+
149180
@pytest.fixture
150181
def lxml_parser():
151182
return etree.XMLParser(resolve_entities=False)

0 commit comments

Comments
 (0)