Left: | ||
Right: |
LEFT | RIGHT |
---|---|
1 # xml.etree test. This file contains enough tests to make sure that | 1 # xml.etree test. This file contains enough tests to make sure that |
flox
2010/02/10 09:34:37
Now the tests guarantee the *same* behaviour betwe
| |
2 # all included components work as they should. For a more extensive | 2 # all included components work as they should. |
3 # test suite, see the selftest script in the ElementTree distribution. | 3 # Large parts are extracted from the upstream test suite. |
4 | |
5 # IMPORTANT: the same doctests are run from "test_xml_etree_c" in | |
6 # order to ensure consistency between the C implementation and the | |
7 # Python implementation. | |
8 # | |
9 # For this purpose, the module-level "ET" symbol is temporarily | |
10 # monkey-patched when running the "test_xml_etree_c" test suite. | |
11 # Don't re-import "xml.etree.ElementTree" module in the docstring, | |
12 # except if the test is specific to the Python implementation. | |
4 | 13 |
5 import sys | 14 import sys |
6 import warnings | |
7 | 15 |
8 from test import test_support | 16 from test import test_support |
9 | 17 |
10 SAMPLE_XML = """ | 18 from xml.etree import ElementTree as ET |
19 | |
20 SAMPLE_XML = """\ | |
11 <body> | 21 <body> |
12 <tag>text</tag> | 22 <tag class='a'>text</tag> |
13 <tag /> | 23 <tag class='b' /> |
14 <section> | 24 <section> |
15 <tag>subtext</tag> | 25 <tag class='b' id='inner'>subtext</tag> |
16 </section> | 26 </section> |
17 </body> | 27 </body> |
28 """ | |
29 | |
30 SAMPLE_SECTION = """\ | |
31 <section> | |
32 <tag class='b' id='inner'>subtext</tag> | |
33 <nexttag /> | |
34 <nextsection> | |
35 <tag /> | |
36 </nextsection> | |
37 </section> | |
18 """ | 38 """ |
19 | 39 |
20 SAMPLE_XML_NS = """ | 40 SAMPLE_XML_NS = """ |
21 <body xmlns="http://effbot.org/ns"> | 41 <body xmlns="http://effbot.org/ns"> |
22 <tag>text</tag> | 42 <tag>text</tag> |
23 <tag /> | 43 <tag /> |
24 <section> | 44 <section> |
25 <tag>subtext</tag> | 45 <tag>subtext</tag> |
26 </section> | 46 </section> |
27 </body> | 47 </body> |
28 """ | 48 """ |
29 | 49 |
50 | |
30 def sanity(): | 51 def sanity(): |
31 """ | 52 """ |
32 Import sanity. | 53 Import sanity. |
33 | 54 |
34 >>> from xml.etree import ElementTree | 55 >>> from xml.etree import ElementTree |
35 >>> from xml.etree import ElementInclude | 56 >>> from xml.etree import ElementInclude |
36 >>> from xml.etree import ElementPath | 57 >>> from xml.etree import ElementPath |
37 """ | 58 """ |
38 | 59 |
39 def check_method(method): | 60 def check_method(method): |
40 if not hasattr(method, '__call__'): | 61 if not hasattr(method, '__call__'): |
41 print method, "not callable" | 62 print method, "not callable" |
42 | 63 |
43 def serialize(ET, elem, to_string=True): | 64 def serialize(elem, to_string=True, **options): |
44 import StringIO | 65 import StringIO |
45 file = StringIO.StringIO() | 66 file = StringIO.StringIO() |
46 tree = ET.ElementTree(elem) | 67 tree = ET.ElementTree(elem) |
47 tree.write(file) | 68 tree.write(file, **options) |
48 if to_string: | 69 if to_string: |
49 return file.getvalue() | 70 return file.getvalue() |
50 else: | 71 else: |
51 file.seek(0) | 72 file.seek(0) |
52 return file | 73 return file |
53 | 74 |
54 def summarize(elem): | 75 def summarize(elem): |
76 if elem.tag == ET.Comment: | |
77 return "<Comment>" | |
55 return elem.tag | 78 return elem.tag |
56 | 79 |
57 def summarize_list(seq): | 80 def summarize_list(seq): |
58 return map(summarize, seq) | 81 return [summarize(elem) for elem in seq] |
82 | |
83 def normalize_crlf(tree): | |
84 for elem in tree.iter(): | |
85 if elem.text: | |
86 elem.text = elem.text.replace("\r\n", "\n") | |
87 if elem.tail: | |
88 elem.tail = elem.tail.replace("\r\n", "\n") | |
89 | |
90 def check_string(string): | |
91 len(string) | |
92 for char in string: | |
93 if len(char) != 1: | |
94 print "expected one-character string, got %r" % char | |
95 new_string = string + "" | |
96 new_string = string + " " | |
97 string[:0] | |
98 | |
99 def check_mapping(mapping): | |
100 len(mapping) | |
101 keys = mapping.keys() | |
102 items = mapping.items() | |
103 for key in keys: | |
104 item = mapping[key] | |
105 mapping["key"] = "value" | |
106 if mapping["key"] != "value": | |
107 print "expected value string, got %r" % mapping["key"] | |
108 | |
109 def check_element(element): | |
110 if not ET.iselement(element): | |
111 print "not an element" | |
112 if not hasattr(element, "tag"): | |
113 print "no tag member" | |
114 if not hasattr(element, "attrib"): | |
115 print "no attrib member" | |
116 if not hasattr(element, "text"): | |
117 print "no text member" | |
118 if not hasattr(element, "tail"): | |
119 print "no tail member" | |
120 | |
121 check_string(element.tag) | |
122 check_mapping(element.attrib) | |
123 if element.text is not None: | |
124 check_string(element.text) | |
125 if element.tail is not None: | |
126 check_string(element.tail) | |
127 for elem in element: | |
128 check_element(elem) | |
129 | |
130 # -------------------------------------------------------------------- | |
131 # element tree tests | |
59 | 132 |
60 def interface(): | 133 def interface(): |
61 """ | 134 """ |
62 Test element tree interface. | 135 Test element tree interface. |
63 | 136 |
64 >>> from xml.etree import ElementTree as ET | 137 >>> element = ET.Element("tag") |
138 >>> check_element(element) | |
139 >>> tree = ET.ElementTree(element) | |
140 >>> check_element(tree.getroot()) | |
65 | 141 |
66 >>> element = ET.Element("tag", key="value") | 142 >>> element = ET.Element("tag", key="value") |
67 >>> tree = ET.ElementTree(element) | 143 >>> tree = ET.ElementTree(element) |
144 >>> repr(element) # doctest: +ELLIPSIS | |
145 "<Element 'tag' at 0x...>" | |
68 | 146 |
69 Make sure all standard element methods exist. | 147 Make sure all standard element methods exist. |
70 | 148 |
71 >>> check_method(element.append) | 149 >>> check_method(element.append) |
150 >>> check_method(element.extend) | |
72 >>> check_method(element.insert) | 151 >>> check_method(element.insert) |
73 >>> check_method(element.remove) | 152 >>> check_method(element.remove) |
74 >>> check_method(element.getchildren) | 153 >>> check_method(element.getchildren) |
75 >>> check_method(element.find) | 154 >>> check_method(element.find) |
155 >>> check_method(element.iterfind) | |
76 >>> check_method(element.findall) | 156 >>> check_method(element.findall) |
77 >>> check_method(element.findtext) | 157 >>> check_method(element.findtext) |
78 >>> check_method(element.clear) | 158 >>> check_method(element.clear) |
79 >>> check_method(element.get) | 159 >>> check_method(element.get) |
80 >>> check_method(element.set) | 160 >>> check_method(element.set) |
81 >>> check_method(element.keys) | 161 >>> check_method(element.keys) |
82 >>> check_method(element.items) | 162 >>> check_method(element.items) |
163 >>> check_method(element.iter) | |
164 >>> check_method(element.itertext) | |
83 >>> check_method(element.getiterator) | 165 >>> check_method(element.getiterator) |
84 | 166 |
85 These methods return an iterable. See bug 6472. | 167 These methods return an iterable. See bug 6472. |
86 | 168 |
87 >>> check_method(element.getiterator("tag").next) | 169 >>> check_method(element.iter("tag").next) |
88 >>> check_method(element.findall("tag").next) | 170 >>> check_method(element.iterfind("tag").next) |
89 >>> check_method(element.findall("*").next) | 171 >>> check_method(element.iterfind("*").next) |
90 | 172 >>> check_method(tree.iter("tag").next) |
173 >>> check_method(tree.iterfind("tag").next) | |
174 >>> check_method(tree.iterfind("*").next) | |
175 | |
176 These aliases are provided: | |
177 | |
178 >>> assert ET.XML == ET.fromstring | |
179 >>> assert ET.PI == ET.ProcessingInstruction | |
180 >>> assert ET.XMLParser == ET.XMLTreeBuilder | |
181 """ | |
182 | |
183 def simpleops(): | |
184 """ | |
91 Basic method sanity checks. | 185 Basic method sanity checks. |
92 | 186 |
93 >>> serialize(ET, element) # 1 | 187 >>> elem = ET.XML("<body><tag/></body>") |
188 >>> serialize(elem) | |
189 '<body><tag /></body>' | |
190 >>> e = ET.Element("tag2") | |
191 >>> elem.append(e) | |
192 >>> serialize(elem) | |
193 '<body><tag /><tag2 /></body>' | |
194 >>> elem.remove(e) | |
195 >>> serialize(elem) | |
196 '<body><tag /></body>' | |
197 >>> elem.insert(0, e) | |
198 >>> serialize(elem) | |
199 '<body><tag2 /><tag /></body>' | |
200 >>> elem.remove(e) | |
201 >>> elem.extend([e]) | |
202 >>> serialize(elem) | |
203 '<body><tag /><tag2 /></body>' | |
204 >>> elem.remove(e) | |
205 | |
206 >>> element = ET.Element("tag", key="value") | |
207 >>> serialize(element) # 1 | |
94 '<tag key="value" />' | 208 '<tag key="value" />' |
95 >>> subelement = ET.Element("subtag") | 209 >>> subelement = ET.Element("subtag") |
96 >>> element.append(subelement) | 210 >>> element.append(subelement) |
97 >>> serialize(ET, element) # 2 | 211 >>> serialize(element) # 2 |
98 '<tag key="value"><subtag /></tag>' | 212 '<tag key="value"><subtag /></tag>' |
99 >>> element.insert(0, subelement) | 213 >>> element.insert(0, subelement) |
100 >>> serialize(ET, element) # 3 | 214 >>> serialize(element) # 3 |
101 '<tag key="value"><subtag /><subtag /></tag>' | 215 '<tag key="value"><subtag /><subtag /></tag>' |
102 >>> element.remove(subelement) | 216 >>> element.remove(subelement) |
103 >>> serialize(ET, element) # 4 | 217 >>> serialize(element) # 4 |
104 '<tag key="value"><subtag /></tag>' | 218 '<tag key="value"><subtag /></tag>' |
105 >>> element.remove(subelement) | 219 >>> element.remove(subelement) |
106 >>> serialize(ET, element) # 5 | 220 >>> serialize(element) # 5 |
107 '<tag key="value" />' | 221 '<tag key="value" />' |
108 >>> element.remove(subelement) | 222 >>> element.remove(subelement) |
109 Traceback (most recent call last): | 223 Traceback (most recent call last): |
110 ValueError: list.remove(x): x not in list | 224 ValueError: list.remove(x): x not in list |
111 >>> serialize(ET, element) # 6 | 225 >>> serialize(element) # 6 |
112 '<tag key="value" />' | 226 '<tag key="value" />' |
113 >>> element[0:0] = [subelement, subelement, subelement] | 227 >>> element[0:0] = [subelement, subelement, subelement] |
114 >>> serialize(ET, element[1]) | 228 >>> serialize(element[1]) |
115 '<subtag />' | 229 '<subtag />' |
116 >>> assert element[1:9] == [element[1], element[2]] | 230 >>> element[1:9] == [element[1], element[2]] |
117 >>> assert element[:9:2] == [element[0], element[2]] | 231 True |
232 >>> element[:9:2] == [element[0], element[2]] | |
233 True | |
118 >>> del element[1:2] | 234 >>> del element[1:2] |
119 >>> serialize(ET, element) | 235 >>> serialize(element) |
120 '<tag key="value"><subtag /><subtag /></tag>' | 236 '<tag key="value"><subtag /><subtag /></tag>' |
121 | 237 """ |
122 Method iterparse should return an iterator. See bug 6472. | 238 |
123 | 239 def cdata(): |
124 >>> next(ET.iterparse(serialize(ET, element, to_string=False))) | 240 """ |
125 ... # doctest: +ELLIPSIS | 241 Test CDATA handling (etc). |
126 ('end', <Element 'subtag' at ...>) | 242 |
243 >>> serialize(ET.XML("<tag>hello</tag>")) | |
244 '<tag>hello</tag>' | |
245 >>> serialize(ET.XML("<tag>hello</tag>")) | |
246 '<tag>hello</tag>' | |
247 >>> serialize(ET.XML("<tag><![CDATA[hello]]></tag>")) | |
248 '<tag>hello</tag>' | |
249 """ | |
250 | |
251 # Only with Python implementation | |
252 def simplefind(): | |
253 """ | |
254 Test find methods using the elementpath fallback. | |
255 | |
256 >>> from xml.etree import ElementTree | |
257 | |
258 >>> CurrentElementPath = ElementTree.ElementPath | |
259 >>> ElementTree.ElementPath = ElementTree._SimpleElementPath() | |
260 >>> elem = ElementTree.XML(SAMPLE_XML) | |
261 >>> elem.find("tag").tag | |
262 'tag' | |
263 >>> ElementTree.ElementTree(elem).find("tag").tag | |
264 'tag' | |
265 >>> elem.findtext("tag") | |
266 'text' | |
267 >>> elem.findtext("tog") | |
268 >>> elem.findtext("tog", "default") | |
269 'default' | |
270 >>> ElementTree.ElementTree(elem).findtext("tag") | |
271 'text' | |
272 >>> summarize_list(elem.findall("tag")) | |
273 ['tag', 'tag'] | |
274 >>> summarize_list(elem.findall(".//tag")) | |
275 ['tag', 'tag', 'tag'] | |
276 | |
277 Path syntax doesn't work in this case. | |
278 | |
279 >>> elem.find("section/tag") | |
280 >>> elem.findtext("section/tag") | |
281 >>> summarize_list(elem.findall("section/tag")) | |
282 [] | |
283 | |
284 >>> ElementTree.ElementPath = CurrentElementPath | |
127 """ | 285 """ |
128 | 286 |
129 def find(): | 287 def find(): |
130 """ | 288 """ |
131 Test find methods (including xpath syntax). | 289 Test find methods (including xpath syntax). |
132 | |
133 >>> from xml.etree import ElementTree as ET | |
134 | 290 |
135 >>> elem = ET.XML(SAMPLE_XML) | 291 >>> elem = ET.XML(SAMPLE_XML) |
136 >>> elem.find("tag").tag | 292 >>> elem.find("tag").tag |
137 'tag' | 293 'tag' |
138 >>> ET.ElementTree(elem).find("tag").tag | 294 >>> ET.ElementTree(elem).find("tag").tag |
139 'tag' | 295 'tag' |
140 >>> elem.find("section/tag").tag | 296 >>> elem.find("section/tag").tag |
141 'tag' | 297 'tag' |
298 >>> elem.find("./tag").tag | |
299 'tag' | |
300 >>> ET.ElementTree(elem).find("./tag").tag | |
301 'tag' | |
302 >>> ET.ElementTree(elem).find("/tag").tag | |
303 'tag' | |
304 >>> elem[2] = ET.XML(SAMPLE_SECTION) | |
305 >>> elem.find("section/nexttag").tag | |
306 'nexttag' | |
142 >>> ET.ElementTree(elem).find("section/tag").tag | 307 >>> ET.ElementTree(elem).find("section/tag").tag |
143 'tag' | 308 'tag' |
309 >>> ET.ElementTree(elem).find("tog") | |
310 >>> ET.ElementTree(elem).find("tog/foo") | |
144 >>> elem.findtext("tag") | 311 >>> elem.findtext("tag") |
145 'text' | 312 'text' |
313 >>> elem.findtext("section/nexttag") | |
314 '' | |
315 >>> elem.findtext("section/nexttag", "default") | |
316 '' | |
146 >>> elem.findtext("tog") | 317 >>> elem.findtext("tog") |
147 >>> elem.findtext("tog", "default") | 318 >>> elem.findtext("tog", "default") |
148 'default' | 319 'default' |
149 >>> ET.ElementTree(elem).findtext("tag") | 320 >>> ET.ElementTree(elem).findtext("tag") |
150 'text' | 321 'text' |
322 >>> ET.ElementTree(elem).findtext("tog/foo") | |
323 >>> ET.ElementTree(elem).findtext("tog/foo", "default") | |
324 'default' | |
325 >>> ET.ElementTree(elem).findtext("./tag") | |
326 'text' | |
327 >>> ET.ElementTree(elem).findtext("/tag") | |
328 'text' | |
151 >>> elem.findtext("section/tag") | 329 >>> elem.findtext("section/tag") |
152 'subtext' | 330 'subtext' |
153 >>> ET.ElementTree(elem).findtext("section/tag") | 331 >>> ET.ElementTree(elem).findtext("section/tag") |
154 'subtext' | 332 'subtext' |
333 >>> summarize_list(elem.findall(".")) | |
334 ['body'] | |
155 >>> summarize_list(elem.findall("tag")) | 335 >>> summarize_list(elem.findall("tag")) |
156 ['tag', 'tag'] | 336 ['tag', 'tag'] |
337 >>> summarize_list(elem.findall("tog")) | |
338 [] | |
339 >>> summarize_list(elem.findall("tog/foo")) | |
340 [] | |
157 >>> summarize_list(elem.findall("*")) | 341 >>> summarize_list(elem.findall("*")) |
158 ['tag', 'tag', 'section'] | 342 ['tag', 'tag', 'section'] |
159 >>> summarize_list(elem.findall(".//tag")) | 343 >>> summarize_list(elem.findall(".//tag")) |
160 ['tag', 'tag', 'tag'] | 344 ['tag', 'tag', 'tag', 'tag'] |
161 >>> summarize_list(elem.findall("section/tag")) | 345 >>> summarize_list(elem.findall("section/tag")) |
162 ['tag'] | 346 ['tag'] |
163 >>> summarize_list(elem.findall("section//tag")) | 347 >>> summarize_list(elem.findall("section//tag")) |
164 ['tag'] | 348 ['tag', 'tag'] |
165 >>> summarize_list(elem.findall("section/*")) | 349 >>> summarize_list(elem.findall("section/*")) |
166 ['tag'] | 350 ['tag', 'nexttag', 'nextsection'] |
167 >>> summarize_list(elem.findall("section//*")) | 351 >>> summarize_list(elem.findall("section//*")) |
168 ['tag'] | 352 ['tag', 'nexttag', 'nextsection', 'tag'] |
169 >>> summarize_list(elem.findall("section/.//*")) | 353 >>> summarize_list(elem.findall("section/.//*")) |
170 ['tag'] | 354 ['tag', 'nexttag', 'nextsection', 'tag'] |
171 >>> summarize_list(elem.findall("*/*")) | 355 >>> summarize_list(elem.findall("*/*")) |
172 ['tag'] | 356 ['tag', 'nexttag', 'nextsection'] |
173 >>> summarize_list(elem.findall("*//*")) | 357 >>> summarize_list(elem.findall("*//*")) |
174 ['tag'] | 358 ['tag', 'nexttag', 'nextsection', 'tag'] |
175 >>> summarize_list(elem.findall("*/tag")) | 359 >>> summarize_list(elem.findall("*/tag")) |
176 ['tag'] | 360 ['tag'] |
177 >>> summarize_list(elem.findall("*/./tag")) | 361 >>> summarize_list(elem.findall("*/./tag")) |
178 ['tag'] | 362 ['tag'] |
179 >>> summarize_list(elem.findall("./tag")) | 363 >>> summarize_list(elem.findall("./tag")) |
180 ['tag', 'tag'] | 364 ['tag', 'tag'] |
181 >>> summarize_list(elem.findall(".//tag")) | 365 >>> summarize_list(elem.findall(".//tag")) |
182 ['tag', 'tag', 'tag'] | 366 ['tag', 'tag', 'tag', 'tag'] |
183 >>> summarize_list(elem.findall("././tag")) | 367 >>> summarize_list(elem.findall("././tag")) |
184 ['tag', 'tag'] | 368 ['tag', 'tag'] |
185 >>> summarize_list(ET.ElementTree(elem).findall("/tag")) | 369 >>> summarize_list(elem.findall(".//tag[@class]")) |
370 ['tag', 'tag', 'tag'] | |
371 >>> summarize_list(elem.findall(".//tag[@class='a']")) | |
372 ['tag'] | |
373 >>> summarize_list(elem.findall(".//tag[@class='b']")) | |
374 ['tag', 'tag'] | |
375 >>> summarize_list(elem.findall(".//tag[@id]")) | |
376 ['tag'] | |
377 >>> summarize_list(elem.findall(".//section[tag]")) | |
378 ['section'] | |
379 >>> summarize_list(elem.findall(".//section[element]")) | |
380 [] | |
381 >>> summarize_list(elem.findall("../tag")) | |
382 [] | |
383 >>> summarize_list(elem.findall("section/../tag")) | |
186 ['tag', 'tag'] | 384 ['tag', 'tag'] |
187 >>> summarize_list(ET.ElementTree(elem).findall("./tag")) | 385 >>> summarize_list(ET.ElementTree(elem).findall("./tag")) |
188 ['tag', 'tag'] | 386 ['tag', 'tag'] |
387 | |
388 Following example is invalid in 1.2. | |
389 A leading '*' is assumed in 1.3. | |
390 | |
391 >>> elem.findall("section//") == elem.findall("section//*") | |
392 True | |
393 | |
394 ET's Path module handles this case incorrectly; this gives | |
395 a warning in 1.3, and the behaviour will be modified in 1.4. | |
396 | |
397 >>> summarize_list(ET.ElementTree(elem).findall("/tag")) | |
398 ['tag', 'tag'] | |
399 | |
189 >>> elem = ET.XML(SAMPLE_XML_NS) | 400 >>> elem = ET.XML(SAMPLE_XML_NS) |
190 >>> summarize_list(elem.findall("tag")) | 401 >>> summarize_list(elem.findall("tag")) |
191 [] | 402 [] |
192 >>> summarize_list(elem.findall("{http://effbot.org/ns}tag")) | 403 >>> summarize_list(elem.findall("{http://effbot.org/ns}tag")) |
193 ['{http://effbot.org/ns}tag', '{http://effbot.org/ns}tag'] | 404 ['{http://effbot.org/ns}tag', '{http://effbot.org/ns}tag'] |
194 >>> summarize_list(elem.findall(".//{http://effbot.org/ns}tag")) | 405 >>> summarize_list(elem.findall(".//{http://effbot.org/ns}tag")) |
195 ['{http://effbot.org/ns}tag', '{http://effbot.org/ns}tag', '{http://effbot.o rg/ns}tag'] | 406 ['{http://effbot.org/ns}tag', '{http://effbot.org/ns}tag', '{http://effbot.o rg/ns}tag'] |
196 """ | 407 """ |
197 | 408 |
409 def file_init(): | |
410 """ | |
411 >>> import StringIO | |
412 | |
413 >>> stringfile = StringIO.StringIO(SAMPLE_XML) | |
414 >>> tree = ET.ElementTree(file=stringfile) | |
415 >>> tree.find("tag").tag | |
416 'tag' | |
417 >>> tree.find("section/tag").tag | |
418 'tag' | |
419 | |
420 >>> tree = ET.ElementTree(file="samples/simple.xml") | |
421 >>> tree.find("element").tag | |
422 'element' | |
423 >>> tree.find("element/../empty-element").tag | |
424 'empty-element' | |
425 """ | |
426 | |
427 def bad_find(): | |
428 """ | |
429 Check bad or unsupported path expressions. | |
430 | |
431 >>> elem = ET.XML(SAMPLE_XML) | |
432 >>> elem.findall("/tag") | |
433 Traceback (most recent call last): | |
434 SyntaxError: cannot use absolute path on element | |
435 """ | |
436 | |
437 def path_cache(): | |
438 """ | |
439 Check that the path cache behaves sanely. | |
440 | |
441 >>> elem = ET.XML(SAMPLE_XML) | |
442 >>> for i in range(10): ET.ElementTree(elem).find('./'+str(i)) | |
443 >>> cache_len_10 = len(ET.ElementPath._cache) | |
444 >>> for i in range(10): ET.ElementTree(elem).find('./'+str(i)) | |
445 >>> len(ET.ElementPath._cache) == cache_len_10 | |
446 True | |
447 >>> for i in range(20): ET.ElementTree(elem).find('./'+str(i)) | |
448 >>> len(ET.ElementPath._cache) > cache_len_10 | |
449 True | |
450 >>> for i in range(600): ET.ElementTree(elem).find('./'+str(i)) | |
451 >>> len(ET.ElementPath._cache) < 500 | |
452 True | |
453 """ | |
454 | |
455 def copy(): | |
456 """ | |
457 Test copy handling (etc). | |
458 | |
459 >>> import copy | |
460 >>> e1 = ET.XML("<tag>hello<foo/></tag>") | |
461 >>> e2 = copy.copy(e1) | |
462 >>> e3 = copy.deepcopy(e1) | |
463 >>> e1.find("foo").tag = "bar" | |
464 >>> serialize(e1) | |
465 '<tag>hello<bar /></tag>' | |
466 >>> serialize(e2) | |
467 '<tag>hello<bar /></tag>' | |
468 >>> serialize(e3) | |
469 '<tag>hello<foo /></tag>' | |
470 | |
471 """ | |
472 | |
473 def attrib(): | |
474 """ | |
475 Test attribute handling. | |
476 | |
477 >>> elem = ET.Element("tag") | |
478 >>> elem.get("key") # 1.1 | |
479 >>> elem.get("key", "default") # 1.2 | |
480 'default' | |
481 >>> elem.set("key", "value") | |
482 >>> elem.get("key") # 1.3 | |
483 'value' | |
484 | |
485 >>> elem = ET.Element("tag", key="value") | |
486 >>> elem.get("key") # 2.1 | |
487 'value' | |
488 >>> elem.attrib # 2.2 | |
489 {'key': 'value'} | |
490 | |
491 >>> attrib = {"key": "value"} | |
492 >>> elem = ET.Element("tag", attrib) | |
493 >>> attrib.clear() # check for aliasing issues | |
494 >>> elem.get("key") # 3.1 | |
495 'value' | |
496 >>> elem.attrib # 3.2 | |
497 {'key': 'value'} | |
498 | |
499 >>> attrib = {"key": "value"} | |
500 >>> elem = ET.Element("tag", **attrib) | |
501 >>> attrib.clear() # check for aliasing issues | |
502 >>> elem.get("key") # 4.1 | |
503 'value' | |
504 >>> elem.attrib # 4.2 | |
505 {'key': 'value'} | |
506 | |
507 >>> elem = ET.Element("tag", {"key": "other"}, key="value") | |
508 >>> elem.get("key") # 5.1 | |
509 'value' | |
510 >>> elem.attrib # 5.2 | |
511 {'key': 'value'} | |
512 | |
513 >>> elem = ET.Element('test') | |
514 >>> elem.text = "aa" | |
515 >>> elem.set('testa', 'testval') | |
516 >>> elem.set('testb', 'test2') | |
517 >>> ET.tostring(elem) | |
518 '<test testa="testval" testb="test2">aa</test>' | |
519 >>> sorted(elem.keys()) | |
520 ['testa', 'testb'] | |
521 >>> sorted(elem.items()) | |
522 [('testa', 'testval'), ('testb', 'test2')] | |
523 >>> elem.attrib['testb'] | |
524 'test2' | |
525 >>> elem.attrib['testb'] = 'test1' | |
526 >>> elem.attrib['testc'] = 'test2' | |
527 >>> ET.tostring(elem) | |
528 '<test testa="testval" testb="test1" testc="test2">aa</test>' | |
529 """ | |
530 | |
531 def makeelement(): | |
532 """ | |
533 Test makeelement handling. | |
534 | |
535 >>> elem = ET.Element("tag") | |
536 >>> attrib = {"key": "value"} | |
537 >>> subelem = elem.makeelement("subtag", attrib) | |
538 >>> if subelem.attrib is attrib: | |
539 ... print "attrib aliasing" | |
540 >>> elem.append(subelem) | |
541 >>> serialize(elem) | |
542 '<tag><subtag key="value" /></tag>' | |
543 | |
544 >>> elem.clear() | |
545 >>> serialize(elem) | |
546 '<tag />' | |
547 >>> elem.append(subelem) | |
548 >>> serialize(elem) | |
549 '<tag><subtag key="value" /></tag>' | |
550 >>> elem.extend([subelem, subelem]) | |
551 >>> serialize(elem) | |
552 '<tag><subtag key="value" /><subtag key="value" /><subtag key="value" /></ta g>' | |
553 >>> elem[:] = [subelem] | |
554 >>> serialize(elem) | |
555 '<tag><subtag key="value" /></tag>' | |
556 >>> elem[:] = tuple([subelem]) | |
557 >>> serialize(elem) | |
558 '<tag><subtag key="value" /></tag>' | |
559 | |
560 """ | |
561 | |
562 def parsefile(): | |
563 """ | |
564 Test parsing from file. | |
565 | |
566 >>> tree = ET.parse("samples/simple.xml") | |
567 >>> normalize_crlf(tree) | |
568 >>> tree.write(sys.stdout) | |
569 <root> | |
570 <element key="value">text</element> | |
571 <element>text</element>tail | |
572 <empty-element /> | |
573 </root> | |
574 >>> tree = ET.parse("samples/simple-ns.xml") | |
575 >>> normalize_crlf(tree) | |
576 >>> tree.write(sys.stdout) | |
577 <ns0:root xmlns:ns0="namespace"> | |
578 <ns0:element key="value">text</ns0:element> | |
579 <ns0:element>text</ns0:element>tail | |
580 <ns0:empty-element /> | |
581 </ns0:root> | |
582 | |
583 >>> parser = ET.XMLParser() | |
584 >>> parser.version # XXX: Upgrade to 2.0.1? | |
585 'Expat 2.0.0' | |
586 >>> parser.feed(open("samples/simple.xml").read()) | |
587 >>> print serialize(parser.close()) | |
588 <root> | |
589 <element key="value">text</element> | |
590 <element>text</element>tail | |
591 <empty-element /> | |
592 </root> | |
593 | |
594 >>> parser = ET.XMLTreeBuilder() # 1.2 compatibility | |
595 >>> parser.feed(open("samples/simple.xml").read()) | |
596 >>> print serialize(parser.close()) | |
597 <root> | |
598 <element key="value">text</element> | |
599 <element>text</element>tail | |
600 <empty-element /> | |
601 </root> | |
602 | |
603 >>> target = ET.TreeBuilder() | |
604 >>> parser = ET.XMLParser(target=target) | |
605 >>> parser.feed(open("samples/simple.xml").read()) | |
606 >>> print serialize(parser.close()) | |
607 <root> | |
608 <element key="value">text</element> | |
609 <element>text</element>tail | |
610 <empty-element /> | |
611 </root> | |
612 """ | |
613 | |
198 def parseliteral(): | 614 def parseliteral(): |
199 r""" | 615 r""" |
200 | |
201 >>> from xml.etree import ElementTree as ET | |
202 | |
203 >>> element = ET.XML("<html><body>text</body></html>") | 616 >>> element = ET.XML("<html><body>text</body></html>") |
204 >>> ET.ElementTree(element).write(sys.stdout) | 617 >>> ET.ElementTree(element).write(sys.stdout) |
205 <html><body>text</body></html> | 618 <html><body>text</body></html> |
206 >>> element = ET.fromstring("<html><body>text</body></html>") | 619 >>> element = ET.fromstring("<html><body>text</body></html>") |
207 >>> ET.ElementTree(element).write(sys.stdout) | 620 >>> ET.ElementTree(element).write(sys.stdout) |
208 <html><body>text</body></html> | 621 <html><body>text</body></html> |
622 >>> sequence = ["<html><body>", "text</bo", "dy></html>"] | |
623 >>> element = ET.fromstringlist(sequence) | |
209 >>> print ET.tostring(element) | 624 >>> print ET.tostring(element) |
625 <html><body>text</body></html> | |
626 >>> print "".join(ET.tostringlist(element)) | |
210 <html><body>text</body></html> | 627 <html><body>text</body></html> |
211 >>> ET.tostring(element, "ascii") | 628 >>> ET.tostring(element, "ascii") |
212 "<?xml version='1.0' encoding='ascii'?>\n<html><body>text</body></html>" | 629 "<?xml version='1.0' encoding='ascii'?>\n<html><body>text</body></html>" |
213 >>> _, ids = ET.XMLID("<html><body>text</body></html>") | 630 >>> _, ids = ET.XMLID("<html><body>text</body></html>") |
214 >>> len(ids) | 631 >>> len(ids) |
215 0 | 632 0 |
216 >>> _, ids = ET.XMLID("<html><body id='body'>text</body></html>") | 633 >>> _, ids = ET.XMLID("<html><body id='body'>text</body></html>") |
217 >>> len(ids) | 634 >>> len(ids) |
218 1 | 635 1 |
219 >>> ids["body"].tag | 636 >>> ids["body"].tag |
220 'body' | 637 'body' |
221 """ | 638 """ |
222 | 639 |
223 def check_encoding(ET, encoding): | 640 def iterparse(): |
224 """ | 641 """ |
225 >>> from xml.etree import ElementTree as ET | 642 Test iterparse interface. |
226 | 643 |
227 >>> check_encoding(ET, "ascii") | 644 >>> iterparse = ET.iterparse |
228 >>> check_encoding(ET, "us-ascii") | 645 |
229 >>> check_encoding(ET, "iso-8859-1") | 646 >>> context = iterparse("samples/simple.xml") |
230 >>> check_encoding(ET, "iso-8859-15") | 647 >>> action, elem = next(context) |
231 >>> check_encoding(ET, "cp437") | 648 >>> print action, elem.tag |
232 >>> check_encoding(ET, "mac-roman") | 649 end element |
650 >>> for action, elem in context: | |
651 ... print action, elem.tag | |
652 end element | |
653 end empty-element | |
654 end root | |
655 >>> context.root.tag | |
656 'root' | |
657 | |
658 >>> context = iterparse("samples/simple-ns.xml") | |
659 >>> for action, elem in context: | |
660 ... print action, elem.tag | |
661 end {namespace}element | |
662 end {namespace}element | |
663 end {namespace}empty-element | |
664 end {namespace}root | |
665 | |
666 >>> events = () | |
667 >>> context = iterparse("samples/simple.xml", events) | |
668 >>> for action, elem in context: | |
669 ... print action, elem.tag | |
670 | |
671 >>> events = () | |
672 >>> context = iterparse("samples/simple.xml", events=events) | |
673 >>> for action, elem in context: | |
674 ... print action, elem.tag | |
675 | |
676 >>> events = ("start", "end") | |
677 >>> context = iterparse("samples/simple.xml", events) | |
678 >>> for action, elem in context: | |
679 ... print action, elem.tag | |
680 start root | |
681 start element | |
682 end element | |
683 start element | |
684 end element | |
685 start empty-element | |
686 end empty-element | |
687 end root | |
688 | |
689 >>> events = ("start", "end", "start-ns", "end-ns") | |
690 >>> context = iterparse("samples/simple-ns.xml", events) | |
691 >>> for action, elem in context: | |
692 ... if action in ("start", "end"): | |
693 ... print action, elem.tag | |
694 ... else: | |
695 ... print action, elem | |
696 start-ns ('', 'namespace') | |
697 start {namespace}root | |
698 start {namespace}element | |
699 end {namespace}element | |
700 start {namespace}element | |
701 end {namespace}element | |
702 start {namespace}empty-element | |
703 end {namespace}empty-element | |
704 end {namespace}root | |
705 end-ns None | |
706 | |
707 >>> events = ("start", "end", "bogus") | |
708 >>> context = iterparse("samples/simple.xml", events) | |
709 Traceback (most recent call last): | |
710 ValueError: unknown event 'bogus' | |
711 | |
712 >>> import StringIO | |
713 | |
714 >>> source = StringIO.StringIO( | |
715 ... "<?xml version='1.0' encoding='iso-8859-1'?>\\n" | |
716 ... "<body xmlns='http://éffbot.org/ns'\\n" | |
717 ... " xmlns:cl\\xe9='http://effbot.org/ns'>text</body>\\n") | |
718 >>> events = ("start-ns",) | |
719 >>> context = iterparse(source, events) | |
720 >>> for action, elem in context: | |
721 ... print action, elem | |
722 start-ns ('', u'http://\\xe9ffbot.org/ns') | |
723 start-ns (u'cl\\xe9', 'http://effbot.org/ns') | |
724 | |
725 >>> source = StringIO.StringIO("<document />junk") | |
726 >>> try: | |
727 ... for action, elem in iterparse(source): | |
728 ... print action, elem.tag | |
729 ... except ET.ParseError, v: | |
730 ... print v | |
731 junk after document element: line 1, column 12 | |
732 """ | |
733 | |
734 def writefile(): | |
735 """ | |
736 >>> elem = ET.Element("tag") | |
737 >>> elem.text = "text" | |
738 >>> serialize(elem) | |
739 '<tag>text</tag>' | |
740 >>> ET.SubElement(elem, "subtag").text = "subtext" | |
741 >>> serialize(elem) | |
742 '<tag>text<subtag>subtext</subtag></tag>' | |
743 | |
744 Test tag suppression | |
745 >>> elem.tag = None | |
746 >>> serialize(elem) | |
747 'text<subtag>subtext</subtag>' | |
748 >>> elem.insert(0, ET.Comment("comment")) | |
749 >>> serialize(elem) # assumes 1.3 | |
750 'text<!--comment--><subtag>subtext</subtag>' | |
751 >>> elem[0] = ET.PI("key", "value") | |
752 >>> serialize(elem) | |
753 'text<?key value?><subtag>subtext</subtag>' | |
754 """ | |
755 | |
756 def custom_builder(): | |
757 """ | |
758 Test parser w. custom builder. | |
759 | |
760 >>> class Builder: | |
761 ... def start(self, tag, attrib): | |
762 ... print "start", tag | |
763 ... def end(self, tag): | |
764 ... print "end", tag | |
765 ... def data(self, text): | |
766 ... pass | |
767 >>> builder = Builder() | |
768 >>> parser = ET.XMLParser(target=builder) | |
769 >>> parser.feed(open("samples/simple.xml", "r").read()) | |
770 start root | |
771 start element | |
772 end element | |
773 start element | |
774 end element | |
775 start empty-element | |
776 end empty-element | |
777 end root | |
778 | |
779 >>> class Builder: | |
780 ... def start(self, tag, attrib): | |
781 ... print "start", tag | |
782 ... def end(self, tag): | |
783 ... print "end", tag | |
784 ... def data(self, text): | |
785 ... pass | |
786 ... def pi(self, target, data): | |
787 ... print "pi", target, repr(data) | |
788 ... def comment(self, data): | |
789 ... print "comment", repr(data) | |
790 >>> builder = Builder() | |
791 >>> parser = ET.XMLParser(target=builder) | |
792 >>> parser.feed(open("samples/simple-ns.xml", "r").read()) | |
793 pi pi 'data' | |
794 comment ' comment ' | |
795 start {namespace}root | |
796 start {namespace}element | |
797 end {namespace}element | |
798 start {namespace}element | |
799 end {namespace}element | |
800 start {namespace}empty-element | |
801 end {namespace}empty-element | |
802 end {namespace}root | |
803 | |
804 """ | |
805 | |
806 def getchildren(): | |
807 """ | |
808 Test Element.getchildren() | |
809 | |
810 >>> tree = ET.parse(open("samples/simple.xml", "r")) | |
811 >>> for elem in tree.getroot().iter(): | |
812 ... summarize_list(elem.getchildren()) | |
813 ['element', 'element', 'empty-element'] | |
814 [] | |
815 [] | |
816 [] | |
817 >>> for elem in tree.getiterator(): | |
818 ... summarize_list(elem.getchildren()) | |
819 ['element', 'element', 'empty-element'] | |
820 [] | |
821 [] | |
822 [] | |
823 | |
824 >>> elem = ET.XML(SAMPLE_XML) | |
825 >>> len(elem.getchildren()) | |
826 3 | |
827 >>> len(elem[2].getchildren()) | |
828 1 | |
829 >>> elem[:] == elem.getchildren() | |
830 True | |
831 >>> child1 = elem[0] | |
832 >>> child2 = elem[2] | |
833 >>> del elem[1:2] | |
834 >>> len(elem.getchildren()) | |
835 2 | |
836 >>> child1 == elem[0] | |
837 True | |
838 >>> child2 == elem[1] | |
839 True | |
840 >>> elem[0:2] = [child2, child1] | |
841 >>> child2 == elem[0] | |
842 True | |
843 >>> child1 == elem[1] | |
844 True | |
845 >>> child1 == elem[0] | |
846 False | |
847 >>> elem.clear() | |
848 >>> elem.getchildren() | |
849 [] | |
850 """ | |
851 | |
852 def writestring(): | |
853 """ | |
854 >>> elem = ET.XML("<html><body>text</body></html>") | |
855 >>> ET.tostring(elem) | |
856 '<html><body>text</body></html>' | |
857 >>> elem = ET.fromstring("<html><body>text</body></html>") | |
858 >>> ET.tostring(elem) | |
859 '<html><body>text</body></html>' | |
860 """ | |
861 | |
862 def check_encoding(encoding): | |
863 """ | |
864 >>> check_encoding("ascii") | |
865 >>> check_encoding("us-ascii") | |
866 >>> check_encoding("iso-8859-1") | |
867 >>> check_encoding("iso-8859-15") | |
868 >>> check_encoding("cp437") | |
869 >>> check_encoding("mac-roman") | |
233 """ | 870 """ |
234 ET.XML("<?xml version='1.0' encoding='%s'?><xml />" % encoding) | 871 ET.XML("<?xml version='1.0' encoding='%s'?><xml />" % encoding) |
235 | 872 |
873 def encoding(): | |
874 r""" | |
875 Test encoding issues. | |
876 | |
877 >>> elem = ET.Element("tag") | |
878 >>> elem.text = u"abc" | |
879 >>> serialize(elem) | |
880 '<tag>abc</tag>' | |
881 >>> serialize(elem, encoding="utf-8") | |
882 '<tag>abc</tag>' | |
883 >>> serialize(elem, encoding="us-ascii") | |
884 '<tag>abc</tag>' | |
885 >>> serialize(elem, encoding="iso-8859-1") | |
886 "<?xml version='1.0' encoding='iso-8859-1'?>\n<tag>abc</tag>" | |
887 | |
888 >>> elem.text = "<&\"\'>" | |
889 >>> serialize(elem) | |
890 '<tag><&"\'></tag>' | |
891 >>> serialize(elem, encoding="utf-8") | |
892 '<tag><&"\'></tag>' | |
893 >>> serialize(elem, encoding="us-ascii") # cdata characters | |
894 '<tag><&"\'></tag>' | |
895 >>> serialize(elem, encoding="iso-8859-1") | |
896 '<?xml version=\'1.0\' encoding=\'iso-8859-1\'?>\n<tag><&"\'></tag >' | |
897 | |
898 >>> elem.attrib["key"] = "<&\"\'>" | |
899 >>> elem.text = None | |
900 >>> serialize(elem) | |
901 '<tag key="<&"\'>" />' | |
902 >>> serialize(elem, encoding="utf-8") | |
903 '<tag key="<&"\'>" />' | |
904 >>> serialize(elem, encoding="us-ascii") | |
905 '<tag key="<&"\'>" />' | |
906 >>> serialize(elem, encoding="iso-8859-1") | |
907 '<?xml version=\'1.0\' encoding=\'iso-8859-1\'?>\n<tag key="<&"\ '>" />' | |
908 | |
909 >>> elem.text = u'\xe5\xf6\xf6<>' | |
910 >>> elem.attrib.clear() | |
911 >>> serialize(elem) | |
912 '<tag>åöö<></tag>' | |
913 >>> serialize(elem, encoding="utf-8") | |
914 '<tag>\xc3\xa5\xc3\xb6\xc3\xb6<></tag>' | |
915 >>> serialize(elem, encoding="us-ascii") | |
916 '<tag>åöö<></tag>' | |
917 >>> serialize(elem, encoding="iso-8859-1") | |
918 "<?xml version='1.0' encoding='iso-8859-1'?>\n<tag>\xe5\xf6\xf6<></tag >" | |
919 | |
920 >>> elem.attrib["key"] = u'\xe5\xf6\xf6<>' | |
921 >>> elem.text = None | |
922 >>> serialize(elem) | |
923 '<tag key="åöö<>" />' | |
924 >>> serialize(elem, encoding="utf-8") | |
925 '<tag key="\xc3\xa5\xc3\xb6\xc3\xb6<>" />' | |
926 >>> serialize(elem, encoding="us-ascii") | |
927 '<tag key="åöö<>" />' | |
928 >>> serialize(elem, encoding="iso-8859-1") | |
929 '<?xml version=\'1.0\' encoding=\'iso-8859-1\'?>\n<tag key="\xe5\xf6\xf6< >" />' | |
930 """ | |
931 | |
932 def methods(): | |
933 r""" | |
934 Test serialization methods. | |
935 | |
936 >>> e = ET.XML("<html><link/><script>1 < 2</script></html>") | |
937 >>> e.tail = "\n" | |
938 >>> serialize(e) | |
939 '<html><link /><script>1 < 2</script></html>\n' | |
940 >>> serialize(e, method=None) | |
941 '<html><link /><script>1 < 2</script></html>\n' | |
942 >>> serialize(e, method="xml") | |
943 '<html><link /><script>1 < 2</script></html>\n' | |
944 >>> serialize(e, method="html") | |
945 '<html><link><script>1 < 2</script></html>\n' | |
946 >>> serialize(e, method="text") | |
947 '1 < 2\n' | |
948 """ | |
949 | |
950 def iterators(): | |
951 """ | |
952 Test iterators. | |
953 | |
954 >>> e = ET.XML("<html><body>this is a <i>paragraph</i>.</body>..</html>") | |
955 >>> summarize_list(e.iter()) | |
956 ['html', 'body', 'i'] | |
957 >>> summarize_list(e.find("body").iter()) | |
958 ['body', 'i'] | |
959 >>> summarize(next(e.iter())) | |
960 'html' | |
961 >>> "".join(e.itertext()) | |
962 'this is a paragraph...' | |
963 >>> "".join(e.find("body").itertext()) | |
964 'this is a paragraph.' | |
965 >>> next(e.itertext()) | |
966 'this is a ' | |
967 | |
968 Method iterparse should return an iterator. See bug 6472. | |
969 | |
970 >>> sourcefile = serialize(e, to_string=False) | |
971 >>> next(ET.iterparse(sourcefile)) # doctest: +ELLIPSIS | |
972 ('end', <Element 'i' at 0x...>) | |
973 | |
974 >>> tree = ET.ElementTree(None) | |
975 >>> tree.iter() | |
976 Traceback (most recent call last): | |
977 AttributeError: 'NoneType' object has no attribute 'iter' | |
978 """ | |
979 | |
980 ENTITY_XML = """\ | |
981 <!DOCTYPE points [ | |
982 <!ENTITY % user-entities SYSTEM 'user-entities.xml'> | |
983 %user-entities; | |
984 ]> | |
985 <document>&entity;</document> | |
986 """ | |
987 | |
988 def entity(): | |
989 """ | |
990 Test entity handling. | |
991 | |
992 1) good entities | |
993 | |
994 >>> e = ET.XML("<document title='舰'>test</document>") | |
995 >>> serialize(e) | |
996 '<document title="舰">test</document>' | |
997 | |
998 2) bad entities | |
999 | |
1000 >>> ET.XML("<document>&entity;</document>") | |
1001 Traceback (most recent call last): | |
1002 ParseError: undefined entity: line 1, column 10 | |
1003 | |
1004 >>> ET.XML(ENTITY_XML) | |
1005 Traceback (most recent call last): | |
1006 ParseError: undefined entity &entity;: line 5, column 10 | |
1007 | |
1008 3) custom entity | |
1009 | |
1010 >>> parser = ET.XMLParser() | |
1011 >>> parser.entity["entity"] = "text" | |
1012 >>> parser.feed(ENTITY_XML) | |
1013 >>> root = parser.close() | |
1014 >>> serialize(root) | |
1015 '<document>text</document>' | |
1016 """ | |
1017 | |
1018 def error(xml): | |
1019 """ | |
1020 | |
1021 Test error handling. | |
1022 | |
1023 >>> issubclass(ET.ParseError, SyntaxError) | |
1024 True | |
1025 >>> error("foo").position | |
1026 (1, 0) | |
1027 >>> error("<tag>&foo;</tag>").position | |
1028 (1, 5) | |
1029 >>> error("foobar<").position | |
1030 (1, 6) | |
1031 | |
1032 """ | |
1033 try: | |
1034 ET.XML(xml) | |
1035 except ET.ParseError: | |
1036 return sys.exc_value | |
1037 | |
1038 def namespace(): | |
1039 """ | |
1040 Test namespace issues. | |
1041 | |
1042 1) xml namespace | |
1043 | |
1044 >>> elem = ET.XML("<tag xml:lang='en' />") | |
1045 >>> serialize(elem) # 1.1 | |
1046 '<tag xml:lang="en" />' | |
1047 | |
1048 2) other "well-known" namespaces | |
1049 | |
1050 >>> elem = ET.XML("<rdf:RDF xmlns:rdf='http://www.w3.org/1999/02/22-rdf-synt ax-ns#' />") | |
1051 >>> serialize(elem) # 2.1 | |
1052 '<rdf:RDF xmlns:rdf="http://www.w3.org/1999/02/22-rdf-syntax-ns#" />' | |
1053 | |
1054 >>> elem = ET.XML("<html:html xmlns:html='http://www.w3.org/1999/xhtml' />") | |
1055 >>> serialize(elem) # 2.2 | |
1056 '<html:html xmlns:html="http://www.w3.org/1999/xhtml" />' | |
1057 | |
1058 >>> elem = ET.XML("<soap:Envelope xmlns:soap='http://schemas.xmlsoap.org/soa p/envelope' />") | |
1059 >>> serialize(elem) # 2.3 | |
1060 '<ns0:Envelope xmlns:ns0="http://schemas.xmlsoap.org/soap/envelope" />' | |
1061 | |
1062 3) unknown namespaces | |
1063 >>> elem = ET.XML(SAMPLE_XML_NS) | |
1064 >>> print serialize(elem) | |
1065 <ns0:body xmlns:ns0="http://effbot.org/ns"> | |
1066 <ns0:tag>text</ns0:tag> | |
1067 <ns0:tag /> | |
1068 <ns0:section> | |
1069 <ns0:tag>subtext</ns0:tag> | |
1070 </ns0:section> | |
1071 </ns0:body> | |
1072 """ | |
1073 | |
1074 def qname(): | |
1075 """ | |
1076 Test QName handling. | |
1077 | |
1078 1) decorated tags | |
1079 | |
1080 >>> elem = ET.Element("{uri}tag") | |
1081 >>> serialize(elem) # 1.1 | |
1082 '<ns0:tag xmlns:ns0="uri" />' | |
1083 >>> elem = ET.Element(ET.QName("{uri}tag")) | |
1084 >>> serialize(elem) # 1.2 | |
1085 '<ns0:tag xmlns:ns0="uri" />' | |
1086 >>> elem = ET.Element(ET.QName("uri", "tag")) | |
1087 >>> serialize(elem) # 1.3 | |
1088 '<ns0:tag xmlns:ns0="uri" />' | |
1089 | |
1090 2) decorated attributes | |
1091 | |
1092 >>> elem.clear() | |
1093 >>> elem.attrib["{uri}key"] = "value" | |
1094 >>> serialize(elem) # 2.1 | |
1095 '<ns0:tag xmlns:ns0="uri" ns0:key="value" />' | |
1096 | |
1097 >>> elem.clear() | |
1098 >>> elem.attrib[ET.QName("{uri}key")] = "value" | |
1099 >>> serialize(elem) # 2.2 | |
1100 '<ns0:tag xmlns:ns0="uri" ns0:key="value" />' | |
1101 | |
1102 3) decorated values are not converted by default, but the | |
1103 QName wrapper can be used for values | |
1104 | |
1105 >>> elem.clear() | |
1106 >>> elem.attrib["{uri}key"] = "{uri}value" | |
1107 >>> serialize(elem) # 3.1 | |
1108 '<ns0:tag xmlns:ns0="uri" ns0:key="{uri}value" />' | |
1109 | |
1110 >>> elem.clear() | |
1111 >>> elem.attrib["{uri}key"] = ET.QName("{uri}value") | |
1112 >>> serialize(elem) # 3.2 | |
1113 '<ns0:tag xmlns:ns0="uri" ns0:key="ns0:value" />' | |
1114 | |
1115 >>> elem.clear() | |
1116 >>> subelem = ET.Element("tag") | |
1117 >>> subelem.attrib["{uri1}key"] = ET.QName("{uri2}value") | |
1118 >>> elem.append(subelem) | |
1119 >>> elem.append(subelem) | |
1120 >>> serialize(elem) # 3.3 | |
1121 '<ns0:tag xmlns:ns0="uri" xmlns:ns1="uri1" xmlns:ns2="uri2"><tag ns1:key="ns 2:value" /><tag ns1:key="ns2:value" /></ns0:tag>' | |
1122 | |
1123 4) Direct QName tests | |
1124 | |
1125 >>> str(ET.QName('ns', 'tag')) | |
1126 '{ns}tag' | |
1127 >>> str(ET.QName('{ns}tag')) | |
1128 '{ns}tag' | |
1129 >>> q1 = ET.QName('ns', 'tag') | |
1130 >>> q2 = ET.QName('ns', 'tag') | |
1131 >>> q1 == q2 | |
1132 True | |
1133 >>> q2 = ET.QName('ns', 'other-tag') | |
1134 >>> q1 == q2 | |
1135 False | |
1136 >>> q1 == 'ns:tag' | |
1137 False | |
1138 >>> q1 == '{ns}tag' | |
1139 True | |
1140 """ | |
1141 | |
1142 def doctype_public(): | |
1143 """ | |
1144 Test PUBLIC doctype. | |
1145 | |
1146 >>> elem = ET.XML('<!DOCTYPE html PUBLIC' | |
1147 ... ' "-//W3C//DTD XHTML 1.0 Transitional//EN"' | |
1148 ... ' "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">' | |
1149 ... '<html>text</html>') | |
1150 | |
1151 """ | |
1152 | |
1153 def xpath_tokenizer(p): | |
1154 """ | |
1155 Test the XPath tokenizer. | |
1156 | |
1157 >>> # tests from the xml specification | |
1158 >>> xpath_tokenizer("*") | |
1159 ['*'] | |
1160 >>> xpath_tokenizer("text()") | |
1161 ['text', '()'] | |
1162 >>> xpath_tokenizer("@name") | |
1163 ['@', 'name'] | |
1164 >>> xpath_tokenizer("@*") | |
1165 ['@', '*'] | |
1166 >>> xpath_tokenizer("para[1]") | |
1167 ['para', '[', '1', ']'] | |
1168 >>> xpath_tokenizer("para[last()]") | |
1169 ['para', '[', 'last', '()', ']'] | |
1170 >>> xpath_tokenizer("*/para") | |
1171 ['*', '/', 'para'] | |
1172 >>> xpath_tokenizer("/doc/chapter[5]/section[2]") | |
1173 ['/', 'doc', '/', 'chapter', '[', '5', ']', '/', 'section', '[', '2', ']'] | |
1174 >>> xpath_tokenizer("chapter//para") | |
1175 ['chapter', '//', 'para'] | |
1176 >>> xpath_tokenizer("//para") | |
1177 ['//', 'para'] | |
1178 >>> xpath_tokenizer("//olist/item") | |
1179 ['//', 'olist', '/', 'item'] | |
1180 >>> xpath_tokenizer(".") | |
1181 ['.'] | |
1182 >>> xpath_tokenizer(".//para") | |
1183 ['.', '//', 'para'] | |
1184 >>> xpath_tokenizer("..") | |
1185 ['..'] | |
1186 >>> xpath_tokenizer("../@lang") | |
1187 ['..', '/', '@', 'lang'] | |
1188 >>> xpath_tokenizer("chapter[title]") | |
1189 ['chapter', '[', 'title', ']'] | |
1190 >>> xpath_tokenizer("employee[@secretary and @assistant]") | |
1191 ['employee', '[', '@', 'secretary', '', 'and', '', '@', 'assistant', ']'] | |
1192 | |
1193 >>> # additional tests | |
1194 >>> xpath_tokenizer("{http://spam}egg") | |
1195 ['{http://spam}egg'] | |
1196 >>> xpath_tokenizer("./spam.egg") | |
1197 ['.', '/', 'spam.egg'] | |
1198 >>> xpath_tokenizer(".//{http://spam}egg") | |
1199 ['.', '//', '{http://spam}egg'] | |
1200 """ | |
1201 from xml.etree import ElementPath | |
1202 out = [] | |
1203 for op, tag in ElementPath.xpath_tokenizer(p): | |
1204 out.append(op or tag) | |
1205 return out | |
1206 | |
236 def processinginstruction(): | 1207 def processinginstruction(): |
237 """ | 1208 """ |
238 Test ProcessingInstruction directly | 1209 Test ProcessingInstruction directly |
239 | |
240 >>> from xml.etree import ElementTree as ET | |
241 | 1210 |
242 >>> ET.tostring(ET.ProcessingInstruction('test', 'instruction')) | 1211 >>> ET.tostring(ET.ProcessingInstruction('test', 'instruction')) |
243 '<?test instruction?>' | 1212 '<?test instruction?>' |
244 >>> ET.tostring(ET.PI('test', 'instruction')) | 1213 >>> ET.tostring(ET.PI('test', 'instruction')) |
245 '<?test instruction?>' | 1214 '<?test instruction?>' |
246 | 1215 |
247 Issue #2746 | 1216 Issue #2746 |
248 | 1217 |
249 >>> ET.tostring(ET.PI('test', '<testing&>')) | 1218 >>> ET.tostring(ET.PI('test', '<testing&>')) |
250 '<?test <testing&>?>' | 1219 '<?test <testing&>?>' |
251 >>> ET.tostring(ET.PI('test', u'<testing&>\xe3'), 'latin1') | 1220 >>> ET.tostring(ET.PI('test', u'<testing&>\xe3'), 'latin1') |
flox
2010/02/10 12:15:38
Backported from py3k: r78126
| |
252 "<?xml version='1.0' encoding='latin1'?>\\n<?test <testing&>\\xe3?>" | 1221 "<?xml version='1.0' encoding='latin1'?>\\n<?test <testing&>\\xe3?>" |
253 | |
254 """ | |
255 | |
256 def check_issue6233(): | |
flox
2010/02/10 12:15:38
Backported from py3k: r78123
| |
257 """ | |
258 >>> from xml.etree import ElementTree as ET | |
259 | |
260 >>> e = ET.XML("<?xml version='1.0' encoding='utf-8'?><body>t\xc3\xa3g</body >") | |
flox
2010/02/10 08:15:27
utf-8 encoded bytes. Should read "t\\xc3\\xa3g".
| |
261 >>> ET.tostring(e, 'ascii') | |
262 "<?xml version='1.0' encoding='ascii'?>\\n<body>tãg</body>" | |
263 >>> e = ET.XML("<?xml version='1.0' encoding='iso-8859-1'?><body>t\\xe3g</bo dy>") | |
flox
2010/02/10 08:15:27
latin-1 encoded bytes
| |
264 >>> ET.tostring(e, 'ascii') | |
265 "<?xml version='1.0' encoding='ascii'?>\\n<body>tãg</body>" | |
266 """ | 1222 """ |
267 | 1223 |
268 # | 1224 # |
269 # xinclude tests (samples from appendix C of the xinclude specification) | 1225 # xinclude tests (samples from appendix C of the xinclude specification) |
270 | 1226 |
271 XINCLUDE = {} | 1227 XINCLUDE = {} |
272 | 1228 |
273 XINCLUDE["C1.xml"] = """\ | 1229 XINCLUDE["C1.xml"] = """\ |
274 <?xml version='1.0'?> | 1230 <?xml version='1.0'?> |
275 <document xmlns:xi="http://www.w3.org/2001/XInclude"> | 1231 <document xmlns:xi="http://www.w3.org/2001/XInclude"> |
(...skipping 69 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
345 | 1301 |
346 def xinclude(): | 1302 def xinclude(): |
347 r""" | 1303 r""" |
348 Basic inclusion example (XInclude C.1) | 1304 Basic inclusion example (XInclude C.1) |
349 | 1305 |
350 >>> from xml.etree import ElementTree as ET | 1306 >>> from xml.etree import ElementTree as ET |
351 >>> from xml.etree import ElementInclude | 1307 >>> from xml.etree import ElementInclude |
352 | 1308 |
353 >>> document = xinclude_loader("C1.xml") | 1309 >>> document = xinclude_loader("C1.xml") |
354 >>> ElementInclude.include(document, xinclude_loader) | 1310 >>> ElementInclude.include(document, xinclude_loader) |
355 >>> print serialize(ET, document) # C1 | 1311 >>> print serialize(document) # C1 |
356 <document> | 1312 <document> |
357 <p>120 Mz is adequate for an average home user.</p> | 1313 <p>120 Mz is adequate for an average home user.</p> |
358 <disclaimer> | 1314 <disclaimer> |
359 <p>The opinions represented herein represent those of the individual | 1315 <p>The opinions represented herein represent those of the individual |
360 and should not be interpreted as official policy endorsed by this | 1316 and should not be interpreted as official policy endorsed by this |
361 organization.</p> | 1317 organization.</p> |
362 </disclaimer> | 1318 </disclaimer> |
363 </document> | 1319 </document> |
364 | 1320 |
365 Textual inclusion example (XInclude C.2) | 1321 Textual inclusion example (XInclude C.2) |
366 | 1322 |
367 >>> document = xinclude_loader("C2.xml") | 1323 >>> document = xinclude_loader("C2.xml") |
368 >>> ElementInclude.include(document, xinclude_loader) | 1324 >>> ElementInclude.include(document, xinclude_loader) |
369 >>> print serialize(ET, document) # C2 | 1325 >>> print serialize(document) # C2 |
370 <document> | 1326 <document> |
371 <p>This document has been accessed | 1327 <p>This document has been accessed |
372 324387 times.</p> | 1328 324387 times.</p> |
373 </document> | 1329 </document> |
374 | 1330 |
375 Textual inclusion of XML example (XInclude C.3) | 1331 Textual inclusion of XML example (XInclude C.3) |
376 | 1332 |
377 >>> document = xinclude_loader("C3.xml") | 1333 >>> document = xinclude_loader("C3.xml") |
378 >>> ElementInclude.include(document, xinclude_loader) | 1334 >>> ElementInclude.include(document, xinclude_loader) |
379 >>> print serialize(ET, document) # C3 | 1335 >>> print serialize(document) # C3 |
380 <document> | 1336 <document> |
381 <p>The following is the source of the "data.xml" resource:</p> | 1337 <p>The following is the source of the "data.xml" resource:</p> |
382 <example><?xml version='1.0'?> | 1338 <example><?xml version='1.0'?> |
383 <data> | 1339 <data> |
384 <item><![CDATA[Brooks & Shields]]></item> | 1340 <item><![CDATA[Brooks & Shields]]></item> |
385 </data> | 1341 </data> |
386 </example> | 1342 </example> |
387 </document> | 1343 </document> |
388 | 1344 |
389 Fallback example (XInclude C.5) | 1345 Fallback example (XInclude C.5) |
390 Note! Fallback support is not yet implemented | 1346 Note! Fallback support is not yet implemented |
391 | 1347 |
392 >>> document = xinclude_loader("C5.xml") | 1348 >>> document = xinclude_loader("C5.xml") |
393 >>> ElementInclude.include(document, xinclude_loader) | 1349 >>> ElementInclude.include(document, xinclude_loader) |
394 Traceback (most recent call last): | 1350 Traceback (most recent call last): |
395 IOError: resource not found | 1351 IOError: resource not found |
396 >>> # print serialize(ET, document) # C5 | 1352 >>> # print serialize(document) # C5 |
397 """ | 1353 """ |
1354 | |
1355 def xinclude_default(): | |
1356 """ | |
1357 >>> from xml.etree import ElementInclude | |
1358 | |
1359 >>> document = xinclude_loader("default.xml") | |
1360 >>> ElementInclude.include(document) | |
1361 >>> print serialize(document) # default | |
1362 <document> | |
1363 <p>Example.</p> | |
1364 <root> | |
1365 <element key="value">text</element> | |
1366 <element>text</element>tail | |
1367 <empty-element /> | |
1368 </root> | |
1369 </document> | |
1370 """ | |
1371 | |
1372 # | |
1373 # badly formatted xi:include tags | |
1374 | |
1375 XINCLUDE_BAD = {} | |
1376 | |
1377 XINCLUDE_BAD["B1.xml"] = """\ | |
1378 <?xml version='1.0'?> | |
1379 <document xmlns:xi="http://www.w3.org/2001/XInclude"> | |
1380 <p>120 Mz is adequate for an average home user.</p> | |
1381 <xi:include href="disclaimer.xml" parse="BAD_TYPE"/> | |
1382 </document> | |
1383 """ | |
1384 | |
1385 XINCLUDE_BAD["B2.xml"] = """\ | |
1386 <?xml version='1.0'?> | |
1387 <div xmlns:xi="http://www.w3.org/2001/XInclude"> | |
1388 <xi:fallback></xi:fallback> | |
1389 </div> | |
1390 """ | |
1391 | |
1392 def xinclude_failures(): | |
1393 r""" | |
1394 Test failure to locate included XML file. | |
1395 | |
1396 >>> from xml.etree import ElementInclude | |
1397 | |
1398 >>> def none_loader(href, parser, encoding=None): | |
1399 ... return None | |
1400 | |
1401 >>> document = ET.XML(XINCLUDE["C1.xml"]) | |
1402 >>> ElementInclude.include(document, loader=none_loader) | |
1403 Traceback (most recent call last): | |
1404 FatalIncludeError: cannot load 'disclaimer.xml' as 'xml' | |
1405 | |
1406 Test failure to locate included text file. | |
1407 | |
1408 >>> document = ET.XML(XINCLUDE["C2.xml"]) | |
1409 >>> ElementInclude.include(document, loader=none_loader) | |
1410 Traceback (most recent call last): | |
1411 FatalIncludeError: cannot load 'count.txt' as 'text' | |
1412 | |
1413 Test bad parse type. | |
1414 | |
1415 >>> document = ET.XML(XINCLUDE_BAD["B1.xml"]) | |
1416 >>> ElementInclude.include(document, loader=none_loader) | |
1417 Traceback (most recent call last): | |
1418 FatalIncludeError: unknown parse type in xi:include tag ('BAD_TYPE') | |
1419 | |
1420 Test xi:fallback outside xi:include. | |
1421 | |
1422 >>> document = ET.XML(XINCLUDE_BAD["B2.xml"]) | |
1423 >>> ElementInclude.include(document, loader=none_loader) | |
1424 Traceback (most recent call last): | |
1425 FatalIncludeError: xi:fallback tag must be child of xi:include ('{http://www .w3.org/2001/XInclude}fallback') | |
1426 """ | |
1427 | |
1428 # -------------------------------------------------------------------- | |
1429 # reported bugs | |
1430 | |
1431 def bug_xmltoolkit21(): | |
1432 """ | |
1433 | |
1434 marshaller gives obscure errors for non-string values | |
1435 | |
1436 >>> elem = ET.Element(123) | |
1437 >>> serialize(elem) # tag | |
1438 Traceback (most recent call last): | |
1439 TypeError: cannot serialize 123 (type int) | |
1440 >>> elem = ET.Element("elem") | |
1441 >>> elem.text = 123 | |
1442 >>> serialize(elem) # text | |
1443 Traceback (most recent call last): | |
1444 TypeError: cannot serialize 123 (type int) | |
1445 >>> elem = ET.Element("elem") | |
1446 >>> elem.tail = 123 | |
1447 >>> serialize(elem) # tail | |
1448 Traceback (most recent call last): | |
1449 TypeError: cannot serialize 123 (type int) | |
1450 >>> elem = ET.Element("elem") | |
1451 >>> elem.set(123, "123") | |
1452 >>> serialize(elem) # attribute key | |
1453 Traceback (most recent call last): | |
1454 TypeError: cannot serialize 123 (type int) | |
1455 >>> elem = ET.Element("elem") | |
1456 >>> elem.set("123", 123) | |
1457 >>> serialize(elem) # attribute value | |
1458 Traceback (most recent call last): | |
1459 TypeError: cannot serialize 123 (type int) | |
1460 | |
1461 """ | |
1462 | |
1463 def bug_xmltoolkit25(): | |
1464 """ | |
1465 | |
1466 typo in ElementTree.findtext | |
1467 | |
1468 >>> elem = ET.XML(SAMPLE_XML) | |
1469 >>> tree = ET.ElementTree(elem) | |
1470 >>> tree.findtext("tag") | |
1471 'text' | |
1472 >>> tree.findtext("section/tag") | |
1473 'subtext' | |
1474 | |
1475 """ | |
1476 | |
1477 def bug_xmltoolkit28(): | |
1478 """ | |
1479 | |
1480 .//tag causes exceptions | |
1481 | |
1482 >>> tree = ET.XML("<doc><table><tbody/></table></doc>") | |
1483 >>> summarize_list(tree.findall(".//thead")) | |
1484 [] | |
1485 >>> summarize_list(tree.findall(".//tbody")) | |
1486 ['tbody'] | |
1487 | |
1488 """ | |
1489 | |
1490 def bug_xmltoolkitX1(): | |
1491 """ | |
1492 | |
1493 dump() doesn't flush the output buffer | |
1494 | |
1495 >>> tree = ET.XML("<doc><table><tbody/></table></doc>") | |
1496 >>> ET.dump(tree); sys.stdout.write("tail") | |
1497 <doc><table><tbody /></table></doc> | |
1498 tail | |
1499 | |
1500 """ | |
1501 | |
1502 def bug_xmltoolkit39(): | |
1503 """ | |
1504 | |
1505 non-ascii element and attribute names doesn't work | |
1506 | |
1507 >>> tree = ET.XML("<?xml version='1.0' encoding='iso-8859-1'?><t\xe4g />") | |
1508 >>> ET.tostring(tree, "utf-8") | |
1509 '<t\\xc3\\xa4g />' | |
1510 | |
1511 >>> tree = ET.XML("<?xml version='1.0' encoding='iso-8859-1'?><tag \xe4ttr=' välue' />") | |
1512 >>> tree.attrib | |
1513 {u'\\xe4ttr': u'v\\xe4lue'} | |
1514 >>> ET.tostring(tree, "utf-8") | |
1515 '<tag \\xc3\\xa4ttr="v\\xc3\\xa4lue" />' | |
1516 | |
1517 >>> tree = ET.XML("<?xml version='1.0' encoding='iso-8859-1'?><t\xe4g>text</ t\xe4g>") | |
1518 >>> ET.tostring(tree, "utf-8") | |
1519 '<t\\xc3\\xa4g>text</t\\xc3\\xa4g>' | |
1520 | |
1521 >>> tree = ET.Element(u"t\u00e4g") | |
1522 >>> ET.tostring(tree, "utf-8") | |
1523 '<t\\xc3\\xa4g />' | |
1524 | |
1525 >>> tree = ET.Element("tag") | |
1526 >>> tree.set(u"\u00e4ttr", u"v\u00e4lue") | |
1527 >>> ET.tostring(tree, "utf-8") | |
1528 '<tag \\xc3\\xa4ttr="v\\xc3\\xa4lue" />' | |
1529 | |
1530 """ | |
1531 | |
1532 def bug_xmltoolkit54(): | |
1533 """ | |
1534 | |
1535 problems handling internally defined entities | |
1536 | |
1537 >>> e = ET.XML("<!DOCTYPE doc [<!ENTITY ldots '舰'>]><doc>&ldots;</doc >") | |
1538 >>> serialize(e) | |
1539 '<doc>舰</doc>' | |
1540 | |
1541 """ | |
1542 | |
1543 def bug_xmltoolkit55(): | |
1544 """ | |
1545 | |
1546 make sure we're reporting the first error, not the last | |
1547 | |
1548 >>> e = ET.XML("<!DOCTYPE doc SYSTEM 'doc.dtd'><doc>&ldots;&ndots;&rdots;</d oc>") | |
1549 Traceback (most recent call last): | |
1550 ParseError: undefined entity &ldots;: line 1, column 36 | |
1551 | |
1552 """ | |
1553 | |
1554 class ExceptionFile: | |
1555 def read(self, x): | |
1556 raise IOError | |
1557 | |
1558 def xmltoolkit60(): | |
1559 """ | |
1560 | |
1561 Handle crash in stream source. | |
1562 >>> tree = ET.parse(ExceptionFile()) | |
1563 Traceback (most recent call last): | |
1564 IOError | |
1565 | |
1566 """ | |
1567 | |
1568 XMLTOOLKIT62_DOC = """<?xml version="1.0" encoding="UTF-8"?> | |
1569 <!DOCTYPE patent-application-publication SYSTEM "pap-v15-2001-01-31.dtd" []> | |
1570 <patent-application-publication> | |
1571 <subdoc-abstract> | |
1572 <paragraph id="A-0001" lvl="0">A new cultivar of Begonia plant named ‘BCT9 801BEG’.</paragraph> | |
1573 </subdoc-abstract> | |
1574 </patent-application-publication>""" | |
1575 | |
1576 | |
1577 def xmltoolkit62(): | |
1578 """ | |
1579 | |
1580 Don't crash when using custom entities. | |
1581 | |
1582 >>> xmltoolkit62() | |
1583 u'A new cultivar of Begonia plant named \u2018BCT9801BEG\u2019.' | |
1584 | |
1585 """ | |
1586 ENTITIES = {u'rsquo': u'\u2019', u'lsquo': u'\u2018'} | |
1587 parser = ET.XMLTreeBuilder() | |
1588 parser.entity.update(ENTITIES) | |
1589 parser.feed(XMLTOOLKIT62_DOC) | |
1590 t = parser.close() | |
1591 return t.find('.//paragraph').text | |
1592 | |
1593 def xmltoolkit63(): | |
1594 """ | |
1595 | |
1596 Check reference leak. | |
1597 >>> xmltoolkit63() | |
1598 >>> count = sys.getrefcount(None) | |
1599 >>> for i in range(1000): | |
1600 ... xmltoolkit63() | |
1601 >>> sys.getrefcount(None) - count | |
1602 0 | |
1603 | |
1604 """ | |
1605 tree = ET.TreeBuilder() | |
1606 tree.start("tag", {}) | |
1607 tree.data("text") | |
1608 tree.end("tag") | |
1609 | |
1610 # -------------------------------------------------------------------- | |
1611 | |
1612 | |
1613 def bug_200708_newline(): | |
1614 r""" | |
1615 | |
1616 Preserve newlines in attributes. | |
1617 | |
1618 >>> e = ET.Element('SomeTag', text="def _f():\n return 3\n") | |
1619 >>> ET.tostring(e) | |
1620 '<SomeTag text="def _f(): return 3 " />' | |
1621 >>> ET.XML(ET.tostring(e)).get("text") | |
1622 'def _f():\n return 3\n' | |
1623 >>> ET.tostring(ET.XML(ET.tostring(e))) | |
1624 '<SomeTag text="def _f(): return 3 " />' | |
1625 | |
1626 """ | |
1627 | |
1628 def bug_200708_close(): | |
1629 """ | |
1630 | |
1631 Test default builder. | |
1632 >>> parser = ET.XMLParser() # default | |
1633 >>> parser.feed("<element>some text</element>") | |
1634 >>> summarize(parser.close()) | |
1635 'element' | |
1636 | |
1637 Test custom builder. | |
1638 >>> class EchoTarget: | |
1639 ... def close(self): | |
1640 ... return ET.Element("element") # simulate root | |
1641 >>> parser = ET.XMLParser(EchoTarget()) | |
1642 >>> parser.feed("<element>some text</element>") | |
1643 >>> summarize(parser.close()) | |
1644 'element' | |
1645 | |
1646 """ | |
1647 | |
1648 def bug_200709_default_namespace(): | |
1649 """ | |
1650 | |
1651 >>> e = ET.Element("{default}elem") | |
1652 >>> s = ET.SubElement(e, "{default}elem") | |
1653 >>> serialize(e, default_namespace="default") # 1 | |
1654 '<elem xmlns="default"><elem /></elem>' | |
1655 | |
1656 >>> e = ET.Element("{default}elem") | |
1657 >>> s = ET.SubElement(e, "{default}elem") | |
1658 >>> s = ET.SubElement(e, "{not-default}elem") | |
1659 >>> serialize(e, default_namespace="default") # 2 | |
1660 '<elem xmlns="default" xmlns:ns1="not-default"><elem /><ns1:elem /></elem>' | |
1661 | |
1662 >>> e = ET.Element("{default}elem") | |
1663 >>> s = ET.SubElement(e, "{default}elem") | |
1664 >>> s = ET.SubElement(e, "elem") # unprefixed name | |
1665 >>> serialize(e, default_namespace="default") # 3 | |
1666 Traceback (most recent call last): | |
1667 ValueError: cannot use non-qualified names with default_namespace option | |
1668 | |
1669 """ | |
1670 | |
1671 def bug_200709_register_namespace(): | |
1672 """ | |
1673 | |
1674 >>> ET.tostring(ET.Element("{http://namespace.invalid/does/not/exist/}title" )) | |
1675 '<ns0:title xmlns:ns0="http://namespace.invalid/does/not/exist/" />' | |
1676 >>> ET.register_namespace("foo", "http://namespace.invalid/does/not/exist/") | |
1677 >>> ET.tostring(ET.Element("{http://namespace.invalid/does/not/exist/}title" )) | |
1678 '<foo:title xmlns:foo="http://namespace.invalid/does/not/exist/" />' | |
1679 | |
1680 And the Dublin Core namespace is in the default list: | |
1681 | |
1682 >>> ET.tostring(ET.Element("{http://purl.org/dc/elements/1.1/}title")) | |
1683 '<dc:title xmlns:dc="http://purl.org/dc/elements/1.1/" />' | |
1684 | |
1685 """ | |
1686 | |
1687 def bug_200709_element_comment(): | |
1688 """ | |
1689 | |
1690 Not sure if this can be fixed, really (since the serializer needs | |
1691 ET.Comment, not cET.comment). | |
1692 | |
1693 >>> a = ET.Element('a') | |
1694 >>> a.append(ET.Comment('foo')) | |
1695 >>> a[0].tag == ET.Comment | |
1696 True | |
1697 | |
1698 >>> a = ET.Element('a') | |
1699 >>> a.append(ET.PI('foo')) | |
1700 >>> a[0].tag == ET.PI | |
1701 True | |
1702 | |
1703 """ | |
1704 | |
1705 def bug_200709_element_insert(): | |
1706 """ | |
1707 | |
1708 >>> a = ET.Element('a') | |
1709 >>> b = ET.SubElement(a, 'b') | |
1710 >>> c = ET.SubElement(a, 'c') | |
1711 >>> d = ET.Element('d') | |
1712 >>> a.insert(0, d) | |
1713 >>> summarize_list(a) | |
1714 ['d', 'b', 'c'] | |
1715 >>> a.insert(-1, d) | |
1716 >>> summarize_list(a) | |
1717 ['d', 'b', 'd', 'c'] | |
1718 | |
1719 """ | |
1720 | |
1721 def bug_200709_iter_comment(): | |
1722 """ | |
1723 | |
1724 >>> a = ET.Element('a') | |
1725 >>> b = ET.SubElement(a, 'b') | |
1726 >>> comment_b = ET.Comment("TEST-b") | |
1727 >>> b.append(comment_b) | |
1728 >>> summarize_list(a.iter(ET.Comment)) | |
1729 ['<Comment>'] | |
1730 | |
1731 """ | |
1732 | |
1733 # -------------------------------------------------------------------- | |
1734 # reported on bugs.python.org | |
398 | 1735 |
399 def bug_1534630(): | 1736 def bug_1534630(): |
flox
2010/02/10 12:15:38
copied from test_xml_etree_c.py (ensure same behav
| |
400 """ | 1737 """ |
401 >>> from xml.etree import ElementTree as ET | |
402 | 1738 |
403 >>> bob = ET.TreeBuilder() | 1739 >>> bob = ET.TreeBuilder() |
404 >>> e = bob.data("data") | 1740 >>> e = bob.data("data") |
405 >>> e = bob.start("tag", {}) | 1741 >>> e = bob.start("tag", {}) |
406 >>> e = bob.end("tag") | 1742 >>> e = bob.end("tag") |
407 >>> e = bob.close() | 1743 >>> e = bob.close() |
408 >>> serialize(ET, e) | 1744 >>> serialize(e) |
409 '<tag />' | 1745 '<tag />' |
410 """ | 1746 |
411 | 1747 """ |
412 def test_main(): | 1748 |
1749 def check_issue6233(): | |
1750 """ | |
1751 | |
1752 >>> e = ET.XML("<?xml version='1.0' encoding='utf-8'?><body>t\\xc3\\xa3g</bo dy>") | |
1753 >>> ET.tostring(e, 'ascii') | |
1754 "<?xml version='1.0' encoding='ascii'?>\\n<body>tãg</body>" | |
1755 >>> e = ET.XML("<?xml version='1.0' encoding='iso-8859-1'?><body>t\\xe3g</bo dy>") | |
1756 >>> ET.tostring(e, 'ascii') | |
1757 "<?xml version='1.0' encoding='ascii'?>\\n<body>tãg</body>" | |
1758 | |
1759 """ | |
1760 | |
1761 def check_issue3151(): | |
1762 """ | |
1763 | |
1764 >>> e = ET.XML('<prefix:localname xmlns:prefix="${stuff}"/>') | |
1765 >>> e.tag | |
1766 '{${stuff}}localname' | |
1767 >>> t = ET.ElementTree(e) | |
1768 >>> ET.tostring(e) | |
1769 '<ns0:localname xmlns:ns0="${stuff}" />' | |
1770 | |
1771 """ | |
1772 | |
1773 def check_issue6565(): | |
1774 """ | |
1775 | |
1776 >>> elem = ET.XML("<body><tag/></body>") | |
1777 >>> summarize_list(elem) | |
1778 ['tag'] | |
1779 >>> newelem = ET.XML(SAMPLE_XML) | |
1780 >>> elem[:] = newelem[:] | |
1781 >>> summarize_list(elem) | |
1782 ['tag', 'tag', 'section'] | |
1783 | |
1784 """ | |
1785 | |
1786 # -------------------------------------------------------------------- | |
1787 | |
1788 | |
1789 class CleanContext(object): | |
1790 """Provide default namespace mapping, path cache and working directory. | |
1791 | |
1792 Save and restore the default namespace mapping and the path cache. | |
1793 Change directory to the "Lib/test/" directory: some tests open | |
1794 xml files in the "samples/" directory relative to the test module. | |
1795 """ | |
1796 def __enter__(self): | |
1797 import os | |
1798 from xml.etree import ElementTree | |
1799 self._nsmap = ElementTree._namespace_map | |
1800 self._path_cache = ElementTree.ElementPath._cache | |
1801 self._previous_cwd = os.getcwd() | |
1802 # Copy the default namespace mapping | |
1803 ElementTree._namespace_map = self._nsmap.copy() | |
1804 # Copy the path cache (should be empty) | |
1805 ElementTree.ElementPath._cache = self._path_cache.copy() | |
1806 # Change directory to Lib/test/ | |
1807 os.chdir(os.path.dirname(__file__)) | |
1808 | |
1809 def __exit__(self, *args): | |
1810 import os | |
1811 from xml.etree import ElementTree | |
1812 # Restore working directory | |
1813 os.chdir(self._previous_cwd) | |
1814 # Restore mapping and path cache | |
1815 ElementTree._namespace_map = self._nsmap | |
1816 ElementTree.ElementPath._cache = self._path_cache | |
1817 | |
1818 | |
1819 def test_main(module_name='xml.etree.ElementTree'): | |
1820 import warnings | |
413 from test import test_xml_etree | 1821 from test import test_xml_etree |
414 with warnings.catch_warnings(): | 1822 def ignore(message, category=DeprecationWarning): |
415 # Ignore warning about search path starting with "/". | 1823 warnings.filterwarnings("ignore", message, category) |
416 warnings.filterwarnings("ignore", | 1824 # The same doctests are used for both the Python and the C implementations |
417 "This search is broken in 1.3 and earlier; if you rely on the " | 1825 assert test_xml_etree.ET.__name__ == module_name |
418 "current behaviour, change it to '.*'", FutureWarning) | 1826 with warnings.catch_warnings(), CleanContext(): |
1827 # Search behaviour is broken if search path starts with "/". | |
1828 ignore("This search is broken in 1.3 and earlier, and will be fixed " | |
1829 "in a future version. If you rely on the current behaviour, " | |
1830 "change it to '.+'", FutureWarning) | |
1831 # Element.getchildren() and Element.getiterator() are deprecated. | |
1832 ignore("This method will be removed in future versions. " | |
1833 "Use .+ instead.") | |
1834 # XMLParser.doctype() is deprecated. | |
1835 ignore("This method of XMLParser is deprecated. " | |
1836 "Define doctype.. method on the TreeBuilder target.") | |
1837 | |
419 test_support.run_doctest(test_xml_etree, verbosity=True) | 1838 test_support.run_doctest(test_xml_etree, verbosity=True) |
1839 | |
1840 # The module should not be changed by the tests | |
1841 assert test_xml_etree.ET.__name__ == module_name | |
420 | 1842 |
421 if __name__ == '__main__': | 1843 if __name__ == '__main__': |
422 test_main() | 1844 test_main() |
LEFT | RIGHT |