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