1
2
3 """
4 Test cases related to XML Schema parsing and validation
5 """
6
7 import unittest, sys, os.path
8
9 this_dir = os.path.dirname(__file__)
10 if this_dir not in sys.path:
11 sys.path.insert(0, this_dir)
12
13 from common_imports import etree, BytesIO, HelperTestCase, fileInTestDir
14 from common_imports import doctest, make_doctest
15
16
19 tree_valid = self.parse('<a><b></b></a>')
20 tree_invalid = self.parse('<a><c></c></a>')
21 schema = self.parse('''
22 <xsd:schema xmlns:xsd="http://www.w3.org/2001/XMLSchema">
23 <xsd:element name="a" type="AType"/>
24 <xsd:complexType name="AType">
25 <xsd:sequence>
26 <xsd:element name="b" type="xsd:string" />
27 </xsd:sequence>
28 </xsd:complexType>
29 </xsd:schema>
30 ''')
31 schema = etree.XMLSchema(schema)
32 self.assertTrue(schema.validate(tree_valid))
33 self.assertFalse(schema.validate(tree_invalid))
34 self.assertTrue(schema.validate(tree_valid))
35 self.assertFalse(schema.validate(tree_invalid))
36
66
68 """We don't have a guarantee that there will always be a path
69 for a _LogEntry object (or even a node for which to determina
70 a path), but at least when this test was created schema validation
71 errors always got a node and an XPath value. If that ever changes,
72 we can modify this test to something like:
73 self.assertTrue(error_path is None or tree_path == error_path)
74 That way, we can at least verify that if we did get a path value
75 it wasn't bogus.
76 """
77 tree = self.parse('<a><b>42</b><b>dada</b></a>')
78 schema = self.parse('''
79 <xsd:schema xmlns:xsd="http://www.w3.org/2001/XMLSchema">
80 <xsd:element name="a" type="AType"/>
81 <xsd:complexType name="AType">
82 <xsd:sequence>
83 <xsd:element name="b" type="xsd:integer" maxOccurs="2"/>
84 </xsd:sequence>
85 </xsd:complexType>
86 </xsd:schema>
87 ''')
88 schema = etree.XMLSchema(schema)
89 schema.validate(tree)
90 tree_path = tree.getpath(tree.findall('b')[1])
91 error_path = schema.error_log[0].path
92 self.assertTrue(tree_path == error_path)
93
95 schema = self.parse('''
96 <xsd:schema xmlns:xsd="http://www.w3.org/2001/XMLSchema">
97 <xsd:element name="a" type="AType"/>
98 <xsd:complexType name="AType">
99 <xsd:sequence minOccurs="4" maxOccurs="4">
100 <xsd:element name="b" type="BType" />
101 </xsd:sequence>
102 </xsd:complexType>
103 <xsd:complexType name="BType">
104 <xsd:attribute name="hardy" type="xsd:string" default="hey" />
105 </xsd:complexType>
106 </xsd:schema>
107 ''')
108 schema = etree.XMLSchema(schema, attribute_defaults=True)
109
110 tree = self.parse('<a><b hardy="ho"/><b/><b hardy="ho"/><b/></a>')
111
112 root = tree.getroot()
113 self.assertEqual('ho', root[0].get('hardy'))
114 self.assertEqual(None, root[1].get('hardy'))
115 self.assertEqual('ho', root[2].get('hardy'))
116 self.assertEqual(None, root[3].get('hardy'))
117
118 self.assertTrue(schema(tree))
119
120 root = tree.getroot()
121 self.assertEqual('ho', root[0].get('hardy'))
122 self.assertEqual('hey', root[1].get('hardy'))
123 self.assertEqual('ho', root[2].get('hardy'))
124 self.assertEqual('hey', root[3].get('hardy'))
125
127 schema = self.parse('''
128 <xsd:schema xmlns:xsd="http://www.w3.org/2001/XMLSchema">
129 <xsd:element name="a" type="AType"/>
130 <xsd:complexType name="AType">
131 <xsd:sequence>
132 <xsd:element name="b" type="xsd:string" />
133 </xsd:sequence>
134 </xsd:complexType>
135 </xsd:schema>
136 ''')
137 schema = etree.XMLSchema(schema)
138 parser = etree.XMLParser(schema=schema)
139
140 tree_valid = self.parse('<a><b></b></a>', parser=parser)
141 self.assertEqual('a', tree_valid.getroot().tag)
142
143 self.assertRaises(etree.XMLSyntaxError,
144 self.parse, '<a><c></c></a>', parser=parser)
145
147
148 schema = self.parse('''
149 <xsd:schema xmlns:xsd="http://www.w3.org/2001/XMLSchema">
150 <xsd:element name="a" type="AType"/>
151 <xsd:complexType name="AType">
152 <xsd:sequence minOccurs="4" maxOccurs="4">
153 <xsd:element name="b" type="BType" />
154 </xsd:sequence>
155 </xsd:complexType>
156 <xsd:complexType name="BType">
157 <xsd:attribute name="hardy" type="xsd:string" default="hey" />
158 </xsd:complexType>
159 </xsd:schema>
160 ''')
161 schema = etree.XMLSchema(schema)
162 parser = etree.XMLParser(schema=schema, attribute_defaults=True)
163
164 tree_valid = self.parse('<a><b hardy="ho"/><b/><b hardy="ho"/><b/></a>',
165 parser=parser)
166 root = tree_valid.getroot()
167 self.assertEqual('ho', root[0].get('hardy'))
168 self.assertEqual('hey', root[1].get('hardy'))
169 self.assertEqual('ho', root[2].get('hardy'))
170 self.assertEqual('hey', root[3].get('hardy'))
171
173
174 schema = self.parse('''
175 <xsd:schema xmlns:xsd="http://www.w3.org/2001/XMLSchema">
176 <xsd:element name="a" type="AType"/>
177 <xsd:complexType name="AType">
178 <xsd:sequence minOccurs="4" maxOccurs="4">
179 <xsd:element name="b" type="BType" />
180 </xsd:sequence>
181 </xsd:complexType>
182 <xsd:complexType name="BType">
183 <xsd:attribute name="hardy" type="xsd:string" default="hey" />
184 </xsd:complexType>
185 </xsd:schema>
186 ''')
187 schema = etree.XMLSchema(schema, attribute_defaults=True)
188 parser = etree.XMLParser(schema=schema)
189
190 tree_valid = self.parse('<a><b hardy="ho"/><b/><b hardy="ho"/><b/></a>',
191 parser=parser)
192 root = tree_valid.getroot()
193 self.assertEqual('ho', root[0].get('hardy'))
194 self.assertEqual('hey', root[1].get('hardy'))
195 self.assertEqual('ho', root[2].get('hardy'))
196 self.assertEqual('hey', root[3].get('hardy'))
197
199
200 schema = self.parse('''
201 <xsd:schema xmlns:xsd="http://www.w3.org/2001/XMLSchema">
202 <xsd:element name="a" type="AType"/>
203 <xsd:complexType name="AType">
204 <xsd:sequence minOccurs="3" maxOccurs="3">
205 <xsd:element name="b" type="BType" />
206 </xsd:sequence>
207 </xsd:complexType>
208 <xsd:complexType name="BType">
209 <xsd:attribute name="hardy" type="xsd:string" fixed="hey" />
210 </xsd:complexType>
211 </xsd:schema>
212 ''')
213 schema = etree.XMLSchema(schema)
214 parser = etree.XMLParser(schema=schema, attribute_defaults=True)
215
216 tree_valid = self.parse('<a><b/><b hardy="hey"/><b/></a>',
217 parser=parser)
218 root = tree_valid.getroot()
219 self.assertEqual('hey', root[0].get('hardy'))
220 self.assertEqual('hey', root[1].get('hardy'))
221 self.assertEqual('hey', root[2].get('hardy'))
222
224 schema_file = BytesIO('''
225 <xsd:schema xmlns:xsd="http://www.w3.org/2001/XMLSchema">
226 <xsd:element name="a" type="AType"/>
227 <xsd:complexType name="AType">
228 <xsd:sequence>
229 <xsd:element name="b" type="xsd:string" />
230 </xsd:sequence>
231 </xsd:complexType>
232 </xsd:schema>
233 ''')
234 schema = etree.XMLSchema(file=schema_file)
235 parser = etree.XMLParser(schema=schema)
236
237 tree_valid = self.parse('<a><b></b></a>', parser=parser)
238 self.assertEqual('a', tree_valid.getroot().tag)
239
240 self.assertRaises(etree.XMLSyntaxError,
241 self.parse, '<a><c></c></a>', parser=parser)
242
244 schema = self.parse('''
245 <xsd:schema xmlns:xsd="http://www.w3.org/2001/XMLSchema">
246 <xsd:element name="a" type="AType"/>
247 <xsd:complexType name="AType">
248 <xsd:sequence>
249 <xsd:element name="b" type="xsd:string" />
250 </xsd:sequence>
251 </xsd:complexType>
252 </xsd:schema>
253 ''')
254 schema = etree.XMLSchema(schema)
255 xml = BytesIO('<a><b></b></a>')
256 events = [ (event, el.tag)
257 for (event, el) in etree.iterparse(xml, schema=schema) ]
258
259 self.assertEqual([('end', 'b'), ('end', 'a')],
260 events)
261
263 schema = self.parse('''
264 <xsd:schema xmlns:xsd="http://www.w3.org/2001/XMLSchema">
265 <xsd:element name="a" type="AType"/>
266 <xsd:complexType name="AType">
267 <xsd:sequence>
268 <xsd:element name="b" type="xsd:string" />
269 </xsd:sequence>
270 </xsd:complexType>
271 </xsd:schema>
272 ''')
273 schema = etree.XMLSchema(schema)
274 self.assertRaises(
275 etree.XMLSyntaxError,
276 list, etree.iterparse(BytesIO('<a><c></c></a>'), schema=schema))
277
280
283
285 schema = self.parse('''
286 <xsd:schema xmlns:xsd="http://www.w3.org/2001/XMLSchema">
287 <xsd:element name="a" type="xsd:string"/>
288 </xsd:schema>
289 ''')
290 schema = etree.XMLSchema(schema)
291
292 root = etree.Element('a')
293 root.text = 'TEST'
294 self.assertTrue(schema(root))
295
296 self.assertRaises(ValueError, schema, etree.Comment('TEST'))
297 self.assertRaises(ValueError, schema, etree.PI('a', 'text'))
298 self.assertRaises(ValueError, schema, etree.Entity('text'))
299
301 schema = self.parse('''\
302 <xsd:schema xmlns:xsd="http://www.w3.org/2001/XMLSchema">
303 <element name="a" type="AType"/>
304 <xsd:complexType name="AType">
305 <xsd:sequence>
306 <xsd:element name="b" type="xsd:string" />
307 </xsd:sequence>
308 </xsd:complexType>
309 </xsd:schema>
310 ''')
311 self.assertRaises(etree.XMLSchemaParseError,
312 etree.XMLSchema, schema)
313
318
329
331
332
333 schema = etree.XMLSchema(file=fileInTestDir('test_import.xsd'))
334 tree_valid = self.parse(
335 '<a:x xmlns:a="http://codespeak.net/lxml/schema/ns1"><b></b></a:x>')
336 self.assertTrue(schema.validate(tree_valid))
337
339 tree_valid = self.parse('<a><b></b></a>')
340 tree_invalid = self.parse('<a><c></c></a>')
341 schema = self.parse('''\
342 <xsd:schema xmlns:xsd="http://www.w3.org/2001/XMLSchema">
343 <xsd:element name="a" type="AType"/>
344 <xsd:complexType name="AType">
345 <xsd:sequence>
346 <xsd:element name="b" type="xsd:string" />
347 </xsd:sequence>
348 </xsd:complexType>
349 </xsd:schema>
350 ''')
351 self.assertTrue(tree_valid.xmlschema(schema))
352 self.assertFalse(tree_invalid.xmlschema(schema))
353
355
356 wsdl = self.parse('''\
357 <wsdl:definitions
358 xmlns:wsdl="http://schemas.xmlsoap.org/wsdl/"
359 xmlns:xs="http://www.w3.org/2001/XMLSchema">
360 <wsdl:types>
361 <xs:schema>
362 </xs:schema>
363 </wsdl:types>
364 </wsdl:definitions>
365 ''')
366 schema_element = wsdl.find(
367 "{http://schemas.xmlsoap.org/wsdl/}types/"
368 "{http://www.w3.org/2001/XMLSchema}schema"
369 )
370 etree.XMLSchema(schema_element)
371 etree.XMLSchema(schema_element)
372 etree.XMLSchema(schema_element)
373
374
376 resolver_schema_int = BytesIO("""\
377 <xsd:schema xmlns:xsd="http://www.w3.org/2001/XMLSchema"
378 xmlns:etype="http://codespeak.net/lxml/test/external"
379 targetNamespace="http://codespeak.net/lxml/test/internal">
380 <xsd:import namespace="http://codespeak.net/lxml/test/external" schemaLocation="XXX.xsd" />
381 <xsd:element name="a" type="etype:AType"/>
382 </xsd:schema>""")
383
384 resolver_schema_int2 = BytesIO("""\
385 <xsd:schema xmlns:xsd="http://www.w3.org/2001/XMLSchema"
386 xmlns:etype="http://codespeak.net/lxml/test/external"
387 targetNamespace="http://codespeak.net/lxml/test/internal">
388 <xsd:import namespace="http://codespeak.net/lxml/test/external" schemaLocation="YYY.xsd" />
389 <xsd:element name="a" type="etype:AType"/>
390 </xsd:schema>""")
391
392 resolver_schema_ext = """\
393 <xsd:schema xmlns:xsd="http://www.w3.org/2001/XMLSchema"
394 targetNamespace="http://codespeak.net/lxml/test/external">
395 <xsd:complexType name="AType">
396 <xsd:sequence><xsd:element name="b" type="xsd:string" minOccurs="0" maxOccurs="unbounded" /></xsd:sequence>
397 </xsd:complexType>
398 </xsd:schema>"""
399
403
404 - def resolve(self, url, id, context):
405 assert url == 'XXX.xsd'
406 return self.resolve_string(self.schema, context)
407
408
409
416
425
427
428
429
430 class res_root(etree.Resolver):
431 def resolve(self, url, id, context):
432 assert False
433 return None
434
435 root_resolver = res_root()
436 etree.get_default_parser().resolvers.add(root_resolver)
437
438 parser = etree.XMLParser()
439 parser.resolvers.add(self.simple_resolver(self.resolver_schema_ext))
440
441 schema_doc = etree.parse(self.resolver_schema_int, parser = parser)
442 schema = etree.XMLSchema(schema_doc)
443 etree.get_default_parser().resolvers.remove(root_resolver)
444
446
447
448 resolver_schema = self.resolver_schema_ext
449
450 class res_nested(etree.Resolver):
451 def __init__(self, ext_schema):
452 self.ext_schema = ext_schema
453
454 def resolve(self, url, id, context):
455 assert url == 'YYY.xsd'
456 return self.resolve_string(self.ext_schema, context)
457
458 class res(etree.Resolver):
459 def __init__(self, ext_schema_1, ext_schema_2):
460 self.ext_schema_1 = ext_schema_1
461 self.ext_schema_2 = ext_schema_2
462
463 def resolve(self, url, id, context):
464 assert url == 'XXX.xsd'
465
466 new_parser = etree.XMLParser()
467 new_parser.resolvers.add(res_nested(self.ext_schema_2))
468 new_schema_doc = etree.parse(self.ext_schema_1, parser = new_parser)
469 new_schema = etree.XMLSchema(new_schema_doc)
470
471 return self.resolve_string(resolver_schema, context)
472
473 parser = etree.XMLParser()
474 parser.resolvers.add(res(self.resolver_schema_int2, self.resolver_schema_ext))
475 schema_doc = etree.parse(self.resolver_schema_int, parser = parser)
476 schema = etree.XMLSchema(schema_doc)
477
478
486
487
488 if __name__ == '__main__':
489 print('to test use test.py %s' % __file__)
490