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 xml = BytesIO('<a><b></b></a>')
275 event, element = next(iter(etree.iterparse(xml, schema=schema)))
276 self.assertEqual('end', event)
277 self.assertEqual('b', element.tag)
278
280 schema = self.parse('''
281 <xsd:schema xmlns:xsd="http://www.w3.org/2001/XMLSchema">
282 <xsd:element name="a" type="AType"/>
283 <xsd:complexType name="AType">
284 <xsd:sequence>
285 <xsd:element name="b" type="xsd:string" />
286 </xsd:sequence>
287 </xsd:complexType>
288 </xsd:schema>
289 ''')
290 schema = etree.XMLSchema(schema)
291 self.assertRaises(
292 etree.XMLSyntaxError,
293 list, etree.iterparse(BytesIO('<a><c></c></a>'), schema=schema))
294
297
300
302 schema = self.parse('''
303 <xsd:schema xmlns:xsd="http://www.w3.org/2001/XMLSchema">
304 <xsd:element name="a" type="xsd:string"/>
305 </xsd:schema>
306 ''')
307 schema = etree.XMLSchema(schema)
308
309 root = etree.Element('a')
310 root.text = 'TEST'
311 self.assertTrue(schema(root))
312
313 self.assertRaises(ValueError, schema, etree.Comment('TEST'))
314 self.assertRaises(ValueError, schema, etree.PI('a', 'text'))
315 self.assertRaises(ValueError, schema, etree.Entity('text'))
316
318 schema = self.parse('''\
319 <xsd:schema xmlns:xsd="http://www.w3.org/2001/XMLSchema">
320 <element name="a" type="AType"/>
321 <xsd:complexType name="AType">
322 <xsd:sequence>
323 <xsd:element name="b" type="xsd:string" />
324 </xsd:sequence>
325 </xsd:complexType>
326 </xsd:schema>
327 ''')
328 self.assertRaises(etree.XMLSchemaParseError,
329 etree.XMLSchema, schema)
330
335
346
348
349
350 schema = etree.XMLSchema(file=fileInTestDir('test_import.xsd'))
351 tree_valid = self.parse(
352 '<a:x xmlns:a="http://codespeak.net/lxml/schema/ns1"><b></b></a:x>')
353 self.assertTrue(schema.validate(tree_valid))
354
356 tree_valid = self.parse('<a><b></b></a>')
357 tree_invalid = self.parse('<a><c></c></a>')
358 schema = self.parse('''\
359 <xsd:schema xmlns:xsd="http://www.w3.org/2001/XMLSchema">
360 <xsd:element name="a" type="AType"/>
361 <xsd:complexType name="AType">
362 <xsd:sequence>
363 <xsd:element name="b" type="xsd:string" />
364 </xsd:sequence>
365 </xsd:complexType>
366 </xsd:schema>
367 ''')
368 self.assertTrue(tree_valid.xmlschema(schema))
369 self.assertFalse(tree_invalid.xmlschema(schema))
370
372
373 wsdl = self.parse('''\
374 <wsdl:definitions
375 xmlns:wsdl="http://schemas.xmlsoap.org/wsdl/"
376 xmlns:xs="http://www.w3.org/2001/XMLSchema">
377 <wsdl:types>
378 <xs:schema>
379 </xs:schema>
380 </wsdl:types>
381 </wsdl:definitions>
382 ''')
383 schema_element = wsdl.find(
384 "{http://schemas.xmlsoap.org/wsdl/}types/"
385 "{http://www.w3.org/2001/XMLSchema}schema"
386 )
387 etree.XMLSchema(schema_element)
388 etree.XMLSchema(schema_element)
389 etree.XMLSchema(schema_element)
390
391
393 resolver_schema_int = BytesIO("""\
394 <xsd:schema xmlns:xsd="http://www.w3.org/2001/XMLSchema"
395 xmlns:etype="http://codespeak.net/lxml/test/external"
396 targetNamespace="http://codespeak.net/lxml/test/internal">
397 <xsd:import namespace="http://codespeak.net/lxml/test/external" schemaLocation="XXX.xsd" />
398 <xsd:element name="a" type="etype:AType"/>
399 </xsd:schema>""")
400
401 resolver_schema_int2 = BytesIO("""\
402 <xsd:schema xmlns:xsd="http://www.w3.org/2001/XMLSchema"
403 xmlns:etype="http://codespeak.net/lxml/test/external"
404 targetNamespace="http://codespeak.net/lxml/test/internal">
405 <xsd:import namespace="http://codespeak.net/lxml/test/external" schemaLocation="YYY.xsd" />
406 <xsd:element name="a" type="etype:AType"/>
407 </xsd:schema>""")
408
409 resolver_schema_ext = """\
410 <xsd:schema xmlns:xsd="http://www.w3.org/2001/XMLSchema"
411 targetNamespace="http://codespeak.net/lxml/test/external">
412 <xsd:complexType name="AType">
413 <xsd:sequence><xsd:element name="b" type="xsd:string" minOccurs="0" maxOccurs="unbounded" /></xsd:sequence>
414 </xsd:complexType>
415 </xsd:schema>"""
416
420
421 - def resolve(self, url, id, context):
422 assert url == 'XXX.xsd'
423 return self.resolve_string(self.schema, context)
424
425
426
433
442
444
445
446
447 class res_root(etree.Resolver):
448 def resolve(self, url, id, context):
449 assert False
450 return None
451
452 root_resolver = res_root()
453 etree.get_default_parser().resolvers.add(root_resolver)
454
455 parser = etree.XMLParser()
456 parser.resolvers.add(self.simple_resolver(self.resolver_schema_ext))
457
458 schema_doc = etree.parse(self.resolver_schema_int, parser = parser)
459 schema = etree.XMLSchema(schema_doc)
460 etree.get_default_parser().resolvers.remove(root_resolver)
461
463
464
465 resolver_schema = self.resolver_schema_ext
466
467 class res_nested(etree.Resolver):
468 def __init__(self, ext_schema):
469 self.ext_schema = ext_schema
470
471 def resolve(self, url, id, context):
472 assert url == 'YYY.xsd'
473 return self.resolve_string(self.ext_schema, context)
474
475 class res(etree.Resolver):
476 def __init__(self, ext_schema_1, ext_schema_2):
477 self.ext_schema_1 = ext_schema_1
478 self.ext_schema_2 = ext_schema_2
479
480 def resolve(self, url, id, context):
481 assert url == 'XXX.xsd'
482
483 new_parser = etree.XMLParser()
484 new_parser.resolvers.add(res_nested(self.ext_schema_2))
485 new_schema_doc = etree.parse(self.ext_schema_1, parser = new_parser)
486 new_schema = etree.XMLSchema(new_schema_doc)
487
488 return self.resolve_string(resolver_schema, context)
489
490 parser = etree.XMLParser()
491 parser.resolvers.add(res(self.resolver_schema_int2, self.resolver_schema_ext))
492 schema_doc = etree.parse(self.resolver_schema_int, parser = parser)
493 schema = etree.XMLSchema(schema_doc)
494
495
503
504
505 if __name__ == '__main__':
506 print('to test use test.py %s' % __file__)
507