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