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