1   
  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)  
 12   
 13  from common_imports import etree, BytesIO, HelperTestCase, fileInTestDir 
 14  from common_imports import doctest, make_doctest 
 15   
 16   
 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))      
 35          self.assertFalse(schema.validate(tree_invalid))   
  36   
 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   
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           
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           
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           
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   
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   
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   
253   
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   
291   
302   
304           
305           
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   
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           
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) 
 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   
376   
377 -        def resolve(self, url, id, context): 
 378              assert url == 'XXX.xsd' 
379              return self.resolve_string(self.schema, context) 
  380   
381       
382   
389   
398   
400           
401           
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   
419           
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   
459   
460   
461  if __name__ == '__main__': 
462      print('to test use test.py %s' % __file__) 
463