Package lxml :: Package tests :: Module test_xmlschema
[hide private]
[frames] | no frames]

Source Code for Module lxml.tests.test_xmlschema

  1  # -*- coding: utf-8 -*- 
  2   
  3  """ 
  4  Test cases related to XML Schema parsing and validation 
  5  """ 
  6   
  7  from __future__ import absolute_import 
  8   
  9  import unittest 
 10   
 11  from .common_imports import etree, BytesIO, HelperTestCase, fileInTestDir, make_doctest 
 12   
 13   
14 -class ETreeXMLSchemaTestCase(HelperTestCase):
15 - def test_xmlschema(self):
16 tree_valid = self.parse('<a><b></b></a>') 17 tree_invalid = self.parse('<a><c></c></a>') 18 schema = self.parse(''' 19 <xsd:schema xmlns:xsd="http://www.w3.org/2001/XMLSchema"> 20 <xsd:element name="a" type="AType"/> 21 <xsd:complexType name="AType"> 22 <xsd:sequence> 23 <xsd:element name="b" type="xsd:string" /> 24 </xsd:sequence> 25 </xsd:complexType> 26 </xsd:schema> 27 ''') 28 schema = etree.XMLSchema(schema) 29 self.assertTrue(schema.validate(tree_valid)) 30 self.assertFalse(schema.validate(tree_invalid)) 31 self.assertTrue(schema.validate(tree_valid)) # retry valid 32 self.assertFalse(schema.validate(tree_invalid)) # retry invalid
33
34 - def test_xmlschema_error_log(self):
35 tree_valid = self.parse('<a><b></b></a>') 36 tree_invalid = self.parse('<a><c></c></a>') 37 schema = self.parse(''' 38 <xsd:schema xmlns:xsd="http://www.w3.org/2001/XMLSchema"> 39 <xsd:element name="a" type="AType"/> 40 <xsd:complexType name="AType"> 41 <xsd:sequence> 42 <xsd:element name="b" type="xsd:string" /> 43 </xsd:sequence> 44 </xsd:complexType> 45 </xsd:schema> 46 ''') 47 schema = etree.XMLSchema(schema) 48 self.assertTrue(schema.validate(tree_valid)) 49 self.assertFalse(schema.error_log.filter_from_errors()) 50 51 self.assertFalse(schema.validate(tree_invalid)) 52 self.assertTrue(schema.error_log.filter_from_errors()) 53 self.assertTrue(schema.error_log.filter_types( 54 etree.ErrorTypes.SCHEMAV_ELEMENT_CONTENT)) 55 56 self.assertTrue(schema.validate(tree_valid)) 57 self.assertFalse(schema.error_log.filter_from_errors()) 58 59 self.assertFalse(schema.validate(tree_invalid)) 60 self.assertTrue(schema.error_log.filter_from_errors()) 61 self.assertTrue(schema.error_log.filter_types( 62 etree.ErrorTypes.SCHEMAV_ELEMENT_CONTENT))
63
65 """We don't have a guarantee that there will always be a path 66 for a _LogEntry object (or even a node for which to determine 67 a path), but at least when this test was created schema validation 68 errors always got a node and an XPath value. If that ever changes, 69 we can modify this test to something like: 70 self.assertTrue(error_path is None or tree_path == error_path) 71 That way, we can at least verify that if we did get a path value 72 it wasn't bogus. 73 """ 74 tree = self.parse('<a><b>42</b><b>dada</b></a>') 75 schema = self.parse(''' 76 <xsd:schema xmlns:xsd="http://www.w3.org/2001/XMLSchema"> 77 <xsd:element name="a" type="AType"/> 78 <xsd:complexType name="AType"> 79 <xsd:sequence> 80 <xsd:element name="b" type="xsd:integer" maxOccurs="2"/> 81 </xsd:sequence> 82 </xsd:complexType> 83 </xsd:schema> 84 ''') 85 schema = etree.XMLSchema(schema) 86 schema.validate(tree) 87 tree_path = tree.getpath(tree.findall('b')[1]) 88 error_path = schema.error_log[0].path 89 self.assertTrue(tree_path == error_path)
90
92 schema = self.parse(''' 93 <xsd:schema xmlns:xsd="http://www.w3.org/2001/XMLSchema"> 94 <xsd:element name="a" type="AType"/> 95 <xsd:complexType name="AType"> 96 <xsd:sequence minOccurs="4" maxOccurs="4"> 97 <xsd:element name="b" type="BType" /> 98 </xsd:sequence> 99 </xsd:complexType> 100 <xsd:complexType name="BType"> 101 <xsd:attribute name="hardy" type="xsd:string" default="hey" /> 102 </xsd:complexType> 103 </xsd:schema> 104 ''') 105 schema = etree.XMLSchema(schema, attribute_defaults=True) 106 107 tree = self.parse('<a><b hardy="ho"/><b/><b hardy="ho"/><b/></a>') 108 109 root = tree.getroot() 110 self.assertEqual('ho', root[0].get('hardy')) 111 self.assertEqual(None, root[1].get('hardy')) 112 self.assertEqual('ho', root[2].get('hardy')) 113 self.assertEqual(None, root[3].get('hardy')) 114 115 self.assertTrue(schema(tree)) 116 117 root = tree.getroot() 118 self.assertEqual('ho', root[0].get('hardy')) 119 self.assertEqual('hey', root[1].get('hardy')) 120 self.assertEqual('ho', root[2].get('hardy')) 121 self.assertEqual('hey', root[3].get('hardy'))
122
123 - def test_xmlschema_parse(self):
124 schema = self.parse(''' 125 <xsd:schema xmlns:xsd="http://www.w3.org/2001/XMLSchema"> 126 <xsd:element name="a" type="AType"/> 127 <xsd:complexType name="AType"> 128 <xsd:sequence> 129 <xsd:element name="b" type="xsd:string" /> 130 </xsd:sequence> 131 </xsd:complexType> 132 </xsd:schema> 133 ''') 134 schema = etree.XMLSchema(schema) 135 parser = etree.XMLParser(schema=schema) 136 137 tree_valid = self.parse('<a><b></b></a>', parser=parser) 138 self.assertEqual('a', tree_valid.getroot().tag) 139 140 self.assertRaises(etree.XMLSyntaxError, 141 self.parse, '<a><c></c></a>', parser=parser)
142
144 # does not work as of libxml2 2.7.3 145 schema = self.parse(''' 146 <xsd:schema xmlns:xsd="http://www.w3.org/2001/XMLSchema"> 147 <xsd:element name="a" type="AType"/> 148 <xsd:complexType name="AType"> 149 <xsd:sequence minOccurs="4" maxOccurs="4"> 150 <xsd:element name="b" type="BType" /> 151 </xsd:sequence> 152 </xsd:complexType> 153 <xsd:complexType name="BType"> 154 <xsd:attribute name="hardy" type="xsd:string" default="hey" /> 155 </xsd:complexType> 156 </xsd:schema> 157 ''') 158 schema = etree.XMLSchema(schema) 159 parser = etree.XMLParser(schema=schema, attribute_defaults=True) 160 161 tree_valid = self.parse('<a><b hardy="ho"/><b/><b hardy="ho"/><b/></a>', 162 parser=parser) 163 root = tree_valid.getroot() 164 self.assertEqual('ho', root[0].get('hardy')) 165 self.assertEqual('hey', root[1].get('hardy')) 166 self.assertEqual('ho', root[2].get('hardy')) 167 self.assertEqual('hey', root[3].get('hardy'))
168
170 # does not work as of libxml2 2.7.3 171 schema = self.parse(''' 172 <xsd:schema xmlns:xsd="http://www.w3.org/2001/XMLSchema"> 173 <xsd:element name="a" type="AType"/> 174 <xsd:complexType name="AType"> 175 <xsd:sequence minOccurs="4" maxOccurs="4"> 176 <xsd:element name="b" type="BType" /> 177 </xsd:sequence> 178 </xsd:complexType> 179 <xsd:complexType name="BType"> 180 <xsd:attribute name="hardy" type="xsd:string" default="hey" /> 181 </xsd:complexType> 182 </xsd:schema> 183 ''') 184 schema = etree.XMLSchema(schema, attribute_defaults=True) 185 parser = etree.XMLParser(schema=schema) 186 187 tree_valid = self.parse('<a><b hardy="ho"/><b/><b hardy="ho"/><b/></a>', 188 parser=parser) 189 root = tree_valid.getroot() 190 self.assertEqual('ho', root[0].get('hardy')) 191 self.assertEqual('hey', root[1].get('hardy')) 192 self.assertEqual('ho', root[2].get('hardy')) 193 self.assertEqual('hey', root[3].get('hardy'))
194
196 # does not work as of libxml2 2.7.3 197 schema = self.parse(''' 198 <xsd:schema xmlns:xsd="http://www.w3.org/2001/XMLSchema"> 199 <xsd:element name="a" type="AType"/> 200 <xsd:complexType name="AType"> 201 <xsd:sequence minOccurs="3" maxOccurs="3"> 202 <xsd:element name="b" type="BType" /> 203 </xsd:sequence> 204 </xsd:complexType> 205 <xsd:complexType name="BType"> 206 <xsd:attribute name="hardy" type="xsd:string" fixed="hey" /> 207 </xsd:complexType> 208 </xsd:schema> 209 ''') 210 schema = etree.XMLSchema(schema) 211 parser = etree.XMLParser(schema=schema, attribute_defaults=True) 212 213 tree_valid = self.parse('<a><b/><b hardy="hey"/><b/></a>', 214 parser=parser) 215 root = tree_valid.getroot() 216 self.assertEqual('hey', root[0].get('hardy')) 217 self.assertEqual('hey', root[1].get('hardy')) 218 self.assertEqual('hey', root[2].get('hardy'))
219
220 - def test_xmlschema_stringio(self):
221 schema_file = BytesIO(''' 222 <xsd:schema xmlns:xsd="http://www.w3.org/2001/XMLSchema"> 223 <xsd:element name="a" type="AType"/> 224 <xsd:complexType name="AType"> 225 <xsd:sequence> 226 <xsd:element name="b" type="xsd:string" /> 227 </xsd:sequence> 228 </xsd:complexType> 229 </xsd:schema> 230 ''') 231 schema = etree.XMLSchema(file=schema_file) 232 parser = etree.XMLParser(schema=schema) 233 234 tree_valid = self.parse('<a><b></b></a>', parser=parser) 235 self.assertEqual('a', tree_valid.getroot().tag) 236 237 self.assertRaises(etree.XMLSyntaxError, 238 self.parse, '<a><c></c></a>', parser=parser)
239
240 - def test_xmlschema_iterparse(self):
241 schema = self.parse(''' 242 <xsd:schema xmlns:xsd="http://www.w3.org/2001/XMLSchema"> 243 <xsd:element name="a" type="AType"/> 244 <xsd:complexType name="AType"> 245 <xsd:sequence> 246 <xsd:element name="b" type="xsd:string" /> 247 </xsd:sequence> 248 </xsd:complexType> 249 </xsd:schema> 250 ''') 251 schema = etree.XMLSchema(schema) 252 xml = BytesIO('<a><b></b></a>') 253 events = [ (event, el.tag) 254 for (event, el) in etree.iterparse(xml, schema=schema) ] 255 256 self.assertEqual([('end', 'b'), ('end', 'a')], 257 events)
258
260 schema = self.parse(''' 261 <xsd:schema xmlns:xsd="http://www.w3.org/2001/XMLSchema"> 262 <xsd:element name="a" type="AType"/> 263 <xsd:complexType name="AType"> 264 <xsd:sequence> 265 <xsd:element name="b" type="xsd:string" /> 266 </xsd:sequence> 267 </xsd:complexType> 268 </xsd:schema> 269 ''') 270 schema = etree.XMLSchema(schema) 271 xml = BytesIO('<a><b></b></a>') 272 event, element = next(iter(etree.iterparse(xml, schema=schema))) 273 self.assertEqual('end', event) 274 self.assertEqual('b', element.tag)
275
277 schema = self.parse(''' 278 <xsd:schema xmlns:xsd="http://www.w3.org/2001/XMLSchema"> 279 <xsd:element name="a" type="AType"/> 280 <xsd:complexType name="AType"> 281 <xsd:sequence> 282 <xsd:element name="b" type="xsd:string" /> 283 </xsd:sequence> 284 </xsd:complexType> 285 </xsd:schema> 286 ''') 287 schema = etree.XMLSchema(schema) 288 self.assertRaises( 289 etree.XMLSyntaxError, 290 list, etree.iterparse(BytesIO('<a><c></c></a>'), schema=schema))
291
293 self.assertRaises(ValueError, etree.XMLSchema, etree.ElementTree())
294
296 self.assertRaises(ValueError, etree.XMLSchema, etree.Comment('TEST'))
297
299 schema = self.parse(''' 300 <xsd:schema xmlns:xsd="http://www.w3.org/2001/XMLSchema"> 301 <xsd:element name="a" type="xsd:string"/> 302 </xsd:schema> 303 ''') 304 schema = etree.XMLSchema(schema) 305 306 root = etree.Element('a') 307 root.text = 'TEST' 308 self.assertTrue(schema(root)) 309 310 self.assertRaises(ValueError, schema, etree.Comment('TEST')) 311 self.assertRaises(ValueError, schema, etree.PI('a', 'text')) 312 self.assertRaises(ValueError, schema, etree.Entity('text'))
313
315 schema = self.parse('''\ 316 <xsd:schema xmlns:xsd="http://www.w3.org/2001/XMLSchema"> 317 <element name="a" type="AType"/> 318 <xsd:complexType name="AType"> 319 <xsd:sequence> 320 <xsd:element name="b" type="xsd:string" /> 321 </xsd:sequence> 322 </xsd:complexType> 323 </xsd:schema> 324 ''') 325 self.assertRaises(etree.XMLSchemaParseError, 326 etree.XMLSchema, schema)
327
329 schema = self.parse('<test/>') 330 self.assertRaises(etree.XMLSchemaParseError, 331 etree.XMLSchema, schema)
332
333 - def test_xmlschema_file(self):
334 # this will only work if we access the file through path or 335 # file object.. 336 f = open(fileInTestDir('test.xsd'), 'rb') 337 try: 338 schema = etree.XMLSchema(file=f) 339 finally: 340 f.close() 341 tree_valid = self.parse('<a><b></b></a>') 342 self.assertTrue(schema.validate(tree_valid))
343
345 # this will only work if we access the file through path or 346 # file object.. 347 schema = etree.XMLSchema(file=fileInTestDir('test_import.xsd')) 348 tree_valid = self.parse( 349 '<a:x xmlns:a="http://codespeak.net/lxml/schema/ns1"><b></b></a:x>') 350 self.assertTrue(schema.validate(tree_valid))
351
352 - def test_xmlschema_shortcut(self):
353 tree_valid = self.parse('<a><b></b></a>') 354 tree_invalid = self.parse('<a><c></c></a>') 355 schema = self.parse('''\ 356 <xsd:schema xmlns:xsd="http://www.w3.org/2001/XMLSchema"> 357 <xsd:element name="a" type="AType"/> 358 <xsd:complexType name="AType"> 359 <xsd:sequence> 360 <xsd:element name="b" type="xsd:string" /> 361 </xsd:sequence> 362 </xsd:complexType> 363 </xsd:schema> 364 ''') 365 self.assertTrue(tree_valid.xmlschema(schema)) 366 self.assertFalse(tree_invalid.xmlschema(schema))
367
369 # this used to crash because the schema part was not properly copied out 370 wsdl = self.parse('''\ 371 <wsdl:definitions 372 xmlns:wsdl="http://schemas.xmlsoap.org/wsdl/" 373 xmlns:xs="http://www.w3.org/2001/XMLSchema"> 374 <wsdl:types> 375 <xs:schema> 376 </xs:schema> 377 </wsdl:types> 378 </wsdl:definitions> 379 ''') 380 schema_element = wsdl.find( 381 "{http://schemas.xmlsoap.org/wsdl/}types/" 382 "{http://www.w3.org/2001/XMLSchema}schema" 383 ) 384 etree.XMLSchema(schema_element) 385 etree.XMLSchema(schema_element) 386 etree.XMLSchema(schema_element)
387 388
389 -class ETreeXMLSchemaResolversTestCase(HelperTestCase):
390 resolver_schema_int = BytesIO("""\ 391 <xsd:schema xmlns:xsd="http://www.w3.org/2001/XMLSchema" 392 xmlns:etype="http://codespeak.net/lxml/test/external" 393 targetNamespace="http://codespeak.net/lxml/test/internal"> 394 <xsd:import namespace="http://codespeak.net/lxml/test/external" schemaLocation="XXX.xsd" /> 395 <xsd:element name="a" type="etype:AType"/> 396 </xsd:schema>""") 397 398 resolver_schema_int2 = BytesIO("""\ 399 <xsd:schema xmlns:xsd="http://www.w3.org/2001/XMLSchema" 400 xmlns:etype="http://codespeak.net/lxml/test/external" 401 targetNamespace="http://codespeak.net/lxml/test/internal"> 402 <xsd:import namespace="http://codespeak.net/lxml/test/external" schemaLocation="YYY.xsd" /> 403 <xsd:element name="a" type="etype:AType"/> 404 </xsd:schema>""") 405 406 resolver_schema_ext = """\ 407 <xsd:schema xmlns:xsd="http://www.w3.org/2001/XMLSchema" 408 targetNamespace="http://codespeak.net/lxml/test/external"> 409 <xsd:complexType name="AType"> 410 <xsd:sequence><xsd:element name="b" type="xsd:string" minOccurs="0" maxOccurs="unbounded" /></xsd:sequence> 411 </xsd:complexType> 412 </xsd:schema>""" 413
414 - class simple_resolver(etree.Resolver):
415 - def __init__(self, schema):
416 self.schema = schema
417
418 - def resolve(self, url, id, context):
419 assert url == 'XXX.xsd' 420 return self.resolve_string(self.schema, context)
421 422 # tests: 423
424 - def test_xmlschema_resolvers(self):
425 # test that resolvers work with schema. 426 parser = etree.XMLParser() 427 parser.resolvers.add(self.simple_resolver(self.resolver_schema_ext)) 428 schema_doc = etree.parse(self.resolver_schema_int, parser = parser) 429 schema = etree.XMLSchema(schema_doc)
430
432 # test that the default resolver will get called if there's no 433 # specific parser resolver. 434 root_resolver = self.simple_resolver(self.resolver_schema_ext) 435 etree.get_default_parser().resolvers.add(root_resolver) 436 schema_doc = etree.parse(self.resolver_schema_int) 437 schema = etree.XMLSchema(schema_doc) 438 etree.get_default_parser().resolvers.remove(root_resolver)
439
441 # test that the default resolver will not get called when a 442 # more specific resolver is registered. 443 444 class res_root(etree.Resolver): 445 def resolve(self, url, id, context): 446 assert False 447 return None
448 449 root_resolver = res_root() 450 etree.get_default_parser().resolvers.add(root_resolver) 451 452 parser = etree.XMLParser() 453 parser.resolvers.add(self.simple_resolver(self.resolver_schema_ext)) 454 455 schema_doc = etree.parse(self.resolver_schema_int, parser = parser) 456 schema = etree.XMLSchema(schema_doc) 457 etree.get_default_parser().resolvers.remove(root_resolver) 458
459 - def test_xmlschema_nested_resolvers(self):
460 # test that resolvers work in a nested fashion. 461 462 resolver_schema = self.resolver_schema_ext 463 464 class res_nested(etree.Resolver): 465 def __init__(self, ext_schema): 466 self.ext_schema = ext_schema
467 468 def resolve(self, url, id, context): 469 assert url == 'YYY.xsd' 470 return self.resolve_string(self.ext_schema, context) 471 472 class res(etree.Resolver): 473 def __init__(self, ext_schema_1, ext_schema_2): 474 self.ext_schema_1 = ext_schema_1 475 self.ext_schema_2 = ext_schema_2 476 477 def resolve(self, url, id, context): 478 assert url == 'XXX.xsd' 479 480 new_parser = etree.XMLParser() 481 new_parser.resolvers.add(res_nested(self.ext_schema_2)) 482 new_schema_doc = etree.parse(self.ext_schema_1, parser = new_parser) 483 new_schema = etree.XMLSchema(new_schema_doc) 484 485 return self.resolve_string(resolver_schema, context) 486 487 parser = etree.XMLParser() 488 parser.resolvers.add(res(self.resolver_schema_int2, self.resolver_schema_ext)) 489 schema_doc = etree.parse(self.resolver_schema_int, parser = parser) 490 schema = etree.XMLSchema(schema_doc) 491 492
493 -def test_suite():
494 suite = unittest.TestSuite() 495 suite.addTests([unittest.makeSuite(ETreeXMLSchemaTestCase)]) 496 suite.addTests([unittest.makeSuite(ETreeXMLSchemaResolversTestCase)]) 497 suite.addTests( 498 [make_doctest('../../../doc/validation.txt')]) 499 return suite
500 501 502 if __name__ == '__main__': 503 print('to test use test.py %s' % __file__) 504