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 327
328 -class ETreeXMLSchemaResolversTestCase(HelperTestCase):
329 resolver_schema_int = BytesIO("""\ 330 <xsd:schema xmlns:xsd="http://www.w3.org/2001/XMLSchema" 331 xmlns:etype="http://codespeak.net/lxml/test/external" 332 targetNamespace="http://codespeak.net/lxml/test/internal"> 333 <xsd:import namespace="http://codespeak.net/lxml/test/external" schemaLocation="XXX.xsd" /> 334 <xsd:element name="a" type="etype:AType"/> 335 </xsd:schema>""") 336 337 resolver_schema_int2 = BytesIO("""\ 338 <xsd:schema xmlns:xsd="http://www.w3.org/2001/XMLSchema" 339 xmlns:etype="http://codespeak.net/lxml/test/external" 340 targetNamespace="http://codespeak.net/lxml/test/internal"> 341 <xsd:import namespace="http://codespeak.net/lxml/test/external" schemaLocation="YYY.xsd" /> 342 <xsd:element name="a" type="etype:AType"/> 343 </xsd:schema>""") 344 345 resolver_schema_ext = """\ 346 <xsd:schema xmlns:xsd="http://www.w3.org/2001/XMLSchema" 347 targetNamespace="http://codespeak.net/lxml/test/external"> 348 <xsd:complexType name="AType"> 349 <xsd:sequence><xsd:element name="b" type="xsd:string" minOccurs="0" maxOccurs="unbounded" /></xsd:sequence> 350 </xsd:complexType> 351 </xsd:schema>""" 352
353 - class simple_resolver(etree.Resolver):
354 - def __init__(self, schema):
355 self.schema = schema
356
357 - def resolve(self, url, id, context):
358 assert url == 'XXX.xsd' 359 return self.resolve_string(self.schema, context)
360 361 # tests: 362
363 - def test_xmlschema_resolvers(self):
364 # test that resolvers work with schema. 365 parser = etree.XMLParser() 366 parser.resolvers.add(self.simple_resolver(self.resolver_schema_ext)) 367 schema_doc = etree.parse(self.resolver_schema_int, parser = parser) 368 schema = etree.XMLSchema(schema_doc)
369
371 # test that the default resolver will get called if there's no 372 # specific parser resolver. 373 root_resolver = self.simple_resolver(self.resolver_schema_ext) 374 etree.get_default_parser().resolvers.add(root_resolver) 375 schema_doc = etree.parse(self.resolver_schema_int) 376 schema = etree.XMLSchema(schema_doc) 377 etree.get_default_parser().resolvers.remove(root_resolver)
378
380 # test that the default resolver will not get called when a 381 # more specific resolver is registered. 382 383 class res_root(etree.Resolver): 384 def resolve(self, url, id, context): 385 assert False 386 return None
387 388 root_resolver = res_root() 389 etree.get_default_parser().resolvers.add(root_resolver) 390 391 parser = etree.XMLParser() 392 parser.resolvers.add(self.simple_resolver(self.resolver_schema_ext)) 393 394 schema_doc = etree.parse(self.resolver_schema_int, parser = parser) 395 schema = etree.XMLSchema(schema_doc) 396 etree.get_default_parser().resolvers.remove(root_resolver) 397
398 - def test_xmlschema_nested_resolvers(self):
399 # test that resolvers work in a nested fashion. 400 401 resolver_schema = self.resolver_schema_ext 402 403 class res_nested(etree.Resolver): 404 def __init__(self, ext_schema): 405 self.ext_schema = ext_schema
406 407 def resolve(self, url, id, context): 408 assert url == 'YYY.xsd' 409 return self.resolve_string(self.ext_schema, context) 410 411 class res(etree.Resolver): 412 def __init__(self, ext_schema_1, ext_schema_2): 413 self.ext_schema_1 = ext_schema_1 414 self.ext_schema_2 = ext_schema_2 415 416 def resolve(self, url, id, context): 417 assert url == 'XXX.xsd' 418 419 new_parser = etree.XMLParser() 420 new_parser.resolvers.add(res_nested(self.ext_schema_2)) 421 new_schema_doc = etree.parse(self.ext_schema_1, parser = new_parser) 422 new_schema = etree.XMLSchema(new_schema_doc) 423 424 return self.resolve_string(resolver_schema, context) 425 426 parser = etree.XMLParser() 427 parser.resolvers.add(res(self.resolver_schema_int2, self.resolver_schema_ext)) 428 schema_doc = etree.parse(self.resolver_schema_int, parser = parser) 429 schema = etree.XMLSchema(schema_doc) 430 431
432 -def test_suite():
433 suite = unittest.TestSuite() 434 suite.addTests([unittest.makeSuite(ETreeXMLSchemaTestCase)]) 435 suite.addTests([unittest.makeSuite(ETreeXMLSchemaResolversTestCase)]) 436 suite.addTests( 437 [make_doctest('../../../doc/validation.txt')]) 438 return suite
439 440 441 if __name__ == '__main__': 442 print('to test use test.py %s' % __file__) 443