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          """We don't have a guarantee that there will always be a path 
 69          for a _LogEntry object (or even a node for which to determina 
 70          a path), but at least when this test was created schema validation 
 71          errors always got a node and an XPath value. If that ever changes, 
 72          we can modify this test to something like: 
 73              self.assertTrue(error_path is None or tree_path == error_path) 
 74          That way, we can at least verify that if we did get a path value 
 75          it wasn't bogus. 
 76          """ 
 77          tree = self.parse('<a><b>42</b><b>dada</b></a>') 
 78          schema = self.parse(''' 
 79  <xsd:schema xmlns:xsd="http://www.w3.org/2001/XMLSchema"> 
 80    <xsd:element name="a" type="AType"/> 
 81    <xsd:complexType name="AType"> 
 82      <xsd:sequence> 
 83        <xsd:element name="b" type="xsd:integer" maxOccurs="2"/> 
 84      </xsd:sequence> 
 85    </xsd:complexType> 
 86  </xsd:schema> 
 87  ''') 
 88          schema = etree.XMLSchema(schema) 
 89          schema.validate(tree) 
 90          tree_path = tree.getpath(tree.findall('b')[1]) 
 91          error_path = schema.error_log[0].path 
 92          self.assertTrue(tree_path == error_path) 
  93   
 95          schema = self.parse(''' 
 96  <xsd:schema xmlns:xsd="http://www.w3.org/2001/XMLSchema"> 
 97    <xsd:element name="a" type="AType"/> 
 98    <xsd:complexType name="AType"> 
 99      <xsd:sequence minOccurs="4" maxOccurs="4"> 
100        <xsd:element name="b" type="BType" /> 
101      </xsd:sequence> 
102    </xsd:complexType> 
103    <xsd:complexType name="BType"> 
104      <xsd:attribute name="hardy" type="xsd:string" default="hey" /> 
105    </xsd:complexType> 
106  </xsd:schema> 
107  ''') 
108          schema = etree.XMLSchema(schema, attribute_defaults=True) 
109   
110          tree = self.parse('<a><b hardy="ho"/><b/><b hardy="ho"/><b/></a>') 
111   
112          root = tree.getroot() 
113          self.assertEqual('ho', root[0].get('hardy')) 
114          self.assertEqual(None, root[1].get('hardy')) 
115          self.assertEqual('ho', root[2].get('hardy')) 
116          self.assertEqual(None, root[3].get('hardy')) 
117   
118          self.assertTrue(schema(tree)) 
119   
120          root = tree.getroot() 
121          self.assertEqual('ho', root[0].get('hardy')) 
122          self.assertEqual('hey', root[1].get('hardy')) 
123          self.assertEqual('ho', root[2].get('hardy')) 
124          self.assertEqual('hey', root[3].get('hardy')) 
 125   
127          schema = self.parse(''' 
128  <xsd:schema xmlns:xsd="http://www.w3.org/2001/XMLSchema"> 
129    <xsd:element name="a" type="AType"/> 
130    <xsd:complexType name="AType"> 
131      <xsd:sequence> 
132        <xsd:element name="b" type="xsd:string" /> 
133      </xsd:sequence> 
134    </xsd:complexType> 
135  </xsd:schema> 
136  ''') 
137          schema = etree.XMLSchema(schema) 
138          parser = etree.XMLParser(schema=schema) 
139   
140          tree_valid = self.parse('<a><b></b></a>', parser=parser) 
141          self.assertEqual('a', tree_valid.getroot().tag) 
142   
143          self.assertRaises(etree.XMLSyntaxError, 
144                            self.parse, '<a><c></c></a>', parser=parser) 
 145   
147           
148          schema = self.parse(''' 
149  <xsd:schema xmlns:xsd="http://www.w3.org/2001/XMLSchema"> 
150    <xsd:element name="a" type="AType"/> 
151    <xsd:complexType name="AType"> 
152      <xsd:sequence minOccurs="4" maxOccurs="4"> 
153        <xsd:element name="b" type="BType" /> 
154      </xsd:sequence> 
155    </xsd:complexType> 
156    <xsd:complexType name="BType"> 
157      <xsd:attribute name="hardy" type="xsd:string" default="hey" /> 
158    </xsd:complexType> 
159  </xsd:schema> 
160  ''') 
161          schema = etree.XMLSchema(schema) 
162          parser = etree.XMLParser(schema=schema, attribute_defaults=True) 
163   
164          tree_valid = self.parse('<a><b hardy="ho"/><b/><b hardy="ho"/><b/></a>', 
165                                  parser=parser) 
166          root = tree_valid.getroot() 
167          self.assertEqual('ho', root[0].get('hardy')) 
168          self.assertEqual('hey', root[1].get('hardy')) 
169          self.assertEqual('ho', root[2].get('hardy')) 
170          self.assertEqual('hey', root[3].get('hardy')) 
 171   
173           
174          schema = self.parse(''' 
175  <xsd:schema xmlns:xsd="http://www.w3.org/2001/XMLSchema"> 
176    <xsd:element name="a" type="AType"/> 
177    <xsd:complexType name="AType"> 
178      <xsd:sequence minOccurs="4" maxOccurs="4"> 
179        <xsd:element name="b" type="BType" /> 
180      </xsd:sequence> 
181    </xsd:complexType> 
182    <xsd:complexType name="BType"> 
183      <xsd:attribute name="hardy" type="xsd:string" default="hey" /> 
184    </xsd:complexType> 
185  </xsd:schema> 
186  ''') 
187          schema = etree.XMLSchema(schema, attribute_defaults=True) 
188          parser = etree.XMLParser(schema=schema) 
189   
190          tree_valid = self.parse('<a><b hardy="ho"/><b/><b hardy="ho"/><b/></a>', 
191                                  parser=parser) 
192          root = tree_valid.getroot() 
193          self.assertEqual('ho', root[0].get('hardy')) 
194          self.assertEqual('hey', root[1].get('hardy')) 
195          self.assertEqual('ho', root[2].get('hardy')) 
196          self.assertEqual('hey', root[3].get('hardy')) 
 197   
199           
200          schema = self.parse(''' 
201  <xsd:schema xmlns:xsd="http://www.w3.org/2001/XMLSchema"> 
202    <xsd:element name="a" type="AType"/> 
203    <xsd:complexType name="AType"> 
204      <xsd:sequence minOccurs="3" maxOccurs="3"> 
205        <xsd:element name="b" type="BType" /> 
206      </xsd:sequence> 
207    </xsd:complexType> 
208    <xsd:complexType name="BType"> 
209      <xsd:attribute name="hardy" type="xsd:string" fixed="hey" /> 
210    </xsd:complexType> 
211  </xsd:schema> 
212  ''') 
213          schema = etree.XMLSchema(schema) 
214          parser = etree.XMLParser(schema=schema, attribute_defaults=True) 
215   
216          tree_valid = self.parse('<a><b/><b hardy="hey"/><b/></a>', 
217                                  parser=parser) 
218          root = tree_valid.getroot() 
219          self.assertEqual('hey', root[0].get('hardy')) 
220          self.assertEqual('hey', root[1].get('hardy')) 
221          self.assertEqual('hey', root[2].get('hardy')) 
 222   
224          schema_file = BytesIO(''' 
225  <xsd:schema xmlns:xsd="http://www.w3.org/2001/XMLSchema"> 
226    <xsd:element name="a" type="AType"/> 
227    <xsd:complexType name="AType"> 
228      <xsd:sequence> 
229        <xsd:element name="b" type="xsd:string" /> 
230      </xsd:sequence> 
231    </xsd:complexType> 
232  </xsd:schema> 
233  ''') 
234          schema = etree.XMLSchema(file=schema_file) 
235          parser = etree.XMLParser(schema=schema) 
236   
237          tree_valid = self.parse('<a><b></b></a>', parser=parser) 
238          self.assertEqual('a', tree_valid.getroot().tag) 
239   
240          self.assertRaises(etree.XMLSyntaxError, 
241                            self.parse, '<a><c></c></a>', parser=parser) 
 242   
244          schema = self.parse(''' 
245  <xsd:schema xmlns:xsd="http://www.w3.org/2001/XMLSchema"> 
246    <xsd:element name="a" type="AType"/> 
247    <xsd:complexType name="AType"> 
248      <xsd:sequence> 
249        <xsd:element name="b" type="xsd:string" /> 
250      </xsd:sequence> 
251    </xsd:complexType> 
252  </xsd:schema> 
253  ''') 
254          schema = etree.XMLSchema(schema) 
255          xml = BytesIO('<a><b></b></a>') 
256          events = [ (event, el.tag) 
257                     for (event, el) in etree.iterparse(xml, schema=schema) ] 
258   
259          self.assertEqual([('end', 'b'), ('end', 'a')], 
260                            events) 
 261   
263          schema = self.parse(''' 
264  <xsd:schema xmlns:xsd="http://www.w3.org/2001/XMLSchema"> 
265    <xsd:element name="a" type="AType"/> 
266    <xsd:complexType name="AType"> 
267      <xsd:sequence> 
268        <xsd:element name="b" type="xsd:string" /> 
269      </xsd:sequence> 
270    </xsd:complexType> 
271  </xsd:schema> 
272  ''') 
273          schema = etree.XMLSchema(schema) 
274          xml = BytesIO('<a><b></b></a>') 
275          event, element = next(iter(etree.iterparse(xml, schema=schema))) 
276          self.assertEqual('end', event) 
277          self.assertEqual('b', element.tag) 
 278   
280          schema = self.parse(''' 
281  <xsd:schema xmlns:xsd="http://www.w3.org/2001/XMLSchema"> 
282    <xsd:element name="a" type="AType"/> 
283    <xsd:complexType name="AType"> 
284      <xsd:sequence> 
285        <xsd:element name="b" type="xsd:string" /> 
286      </xsd:sequence> 
287    </xsd:complexType> 
288  </xsd:schema> 
289  ''') 
290          schema = etree.XMLSchema(schema) 
291          self.assertRaises( 
292              etree.XMLSyntaxError, 
293              list, etree.iterparse(BytesIO('<a><c></c></a>'), schema=schema)) 
 294   
297   
300   
302          schema = self.parse(''' 
303  <xsd:schema xmlns:xsd="http://www.w3.org/2001/XMLSchema"> 
304    <xsd:element name="a" type="xsd:string"/> 
305  </xsd:schema> 
306  ''') 
307          schema = etree.XMLSchema(schema) 
308   
309          root = etree.Element('a') 
310          root.text = 'TEST' 
311          self.assertTrue(schema(root)) 
312   
313          self.assertRaises(ValueError, schema, etree.Comment('TEST')) 
314          self.assertRaises(ValueError, schema, etree.PI('a', 'text')) 
315          self.assertRaises(ValueError, schema, etree.Entity('text')) 
 316   
318          schema = self.parse('''\ 
319  <xsd:schema xmlns:xsd="http://www.w3.org/2001/XMLSchema"> 
320    <element name="a" type="AType"/> 
321    <xsd:complexType name="AType"> 
322      <xsd:sequence> 
323        <xsd:element name="b" type="xsd:string" /> 
324      </xsd:sequence> 
325    </xsd:complexType> 
326  </xsd:schema> 
327  ''') 
328          self.assertRaises(etree.XMLSchemaParseError, 
329                            etree.XMLSchema, schema) 
 330   
335   
346   
348           
349           
350          schema = etree.XMLSchema(file=fileInTestDir('test_import.xsd')) 
351          tree_valid = self.parse( 
352              '<a:x xmlns:a="http://codespeak.net/lxml/schema/ns1"><b></b></a:x>') 
353          self.assertTrue(schema.validate(tree_valid)) 
 354   
356          tree_valid = self.parse('<a><b></b></a>') 
357          tree_invalid = self.parse('<a><c></c></a>') 
358          schema = self.parse('''\ 
359  <xsd:schema xmlns:xsd="http://www.w3.org/2001/XMLSchema"> 
360    <xsd:element name="a" type="AType"/> 
361    <xsd:complexType name="AType"> 
362      <xsd:sequence> 
363        <xsd:element name="b" type="xsd:string" /> 
364      </xsd:sequence> 
365    </xsd:complexType> 
366  </xsd:schema> 
367  ''') 
368          self.assertTrue(tree_valid.xmlschema(schema)) 
369          self.assertFalse(tree_invalid.xmlschema(schema)) 
 370   
372           
373          wsdl = self.parse('''\ 
374  <wsdl:definitions 
375     xmlns:wsdl="http://schemas.xmlsoap.org/wsdl/" 
376     xmlns:xs="http://www.w3.org/2001/XMLSchema"> 
377   <wsdl:types> 
378    <xs:schema> 
379    </xs:schema> 
380   </wsdl:types> 
381  </wsdl:definitions> 
382          ''') 
383          schema_element = wsdl.find( 
384              "{http://schemas.xmlsoap.org/wsdl/}types/" 
385              "{http://www.w3.org/2001/XMLSchema}schema" 
386          ) 
387          etree.XMLSchema(schema_element) 
388          etree.XMLSchema(schema_element) 
389          etree.XMLSchema(schema_element) 
 393      resolver_schema_int = BytesIO("""\ 
394  <xsd:schema xmlns:xsd="http://www.w3.org/2001/XMLSchema" 
395      xmlns:etype="http://codespeak.net/lxml/test/external" 
396      targetNamespace="http://codespeak.net/lxml/test/internal"> 
397          <xsd:import namespace="http://codespeak.net/lxml/test/external" schemaLocation="XXX.xsd" /> 
398          <xsd:element name="a" type="etype:AType"/> 
399  </xsd:schema>""") 
400   
401      resolver_schema_int2 = BytesIO("""\ 
402  <xsd:schema xmlns:xsd="http://www.w3.org/2001/XMLSchema" 
403      xmlns:etype="http://codespeak.net/lxml/test/external" 
404      targetNamespace="http://codespeak.net/lxml/test/internal"> 
405          <xsd:import namespace="http://codespeak.net/lxml/test/external" schemaLocation="YYY.xsd" /> 
406          <xsd:element name="a" type="etype:AType"/> 
407  </xsd:schema>""") 
408   
409      resolver_schema_ext = """\ 
410  <xsd:schema xmlns:xsd="http://www.w3.org/2001/XMLSchema" 
411      targetNamespace="http://codespeak.net/lxml/test/external"> 
412      <xsd:complexType name="AType"> 
413        <xsd:sequence><xsd:element name="b" type="xsd:string" minOccurs="0" maxOccurs="unbounded" /></xsd:sequence> 
414      </xsd:complexType> 
415  </xsd:schema>"""  
416   
420   
421 -        def resolve(self, url, id, context): 
 422              assert url == 'XXX.xsd' 
423              return self.resolve_string(self.schema, context) 
  424   
425       
426   
433   
442   
444           
445           
446   
447          class res_root(etree.Resolver): 
448              def resolve(self, url, id, context): 
449                  assert False 
450                  return None 
  451   
452          root_resolver = res_root() 
453          etree.get_default_parser().resolvers.add(root_resolver) 
454   
455          parser = etree.XMLParser() 
456          parser.resolvers.add(self.simple_resolver(self.resolver_schema_ext)) 
457   
458          schema_doc = etree.parse(self.resolver_schema_int, parser = parser) 
459          schema = etree.XMLSchema(schema_doc) 
460          etree.get_default_parser().resolvers.remove(root_resolver) 
461   
463           
464   
465          resolver_schema = self.resolver_schema_ext 
466   
467          class res_nested(etree.Resolver): 
468              def __init__(self, ext_schema): 
469                  self.ext_schema = ext_schema 
 470   
471              def resolve(self, url, id, context): 
472                  assert url == 'YYY.xsd' 
473                  return self.resolve_string(self.ext_schema, context) 
474   
475          class res(etree.Resolver): 
476              def __init__(self, ext_schema_1, ext_schema_2): 
477                  self.ext_schema_1 = ext_schema_1 
478                  self.ext_schema_2 = ext_schema_2 
479   
480              def resolve(self, url, id, context): 
481                  assert url == 'XXX.xsd' 
482   
483                  new_parser = etree.XMLParser() 
484                  new_parser.resolvers.add(res_nested(self.ext_schema_2)) 
485                  new_schema_doc = etree.parse(self.ext_schema_1, parser = new_parser) 
486                  new_schema = etree.XMLSchema(new_schema_doc) 
487   
488                  return self.resolve_string(resolver_schema, context) 
489   
490          parser = etree.XMLParser() 
491          parser.resolvers.add(res(self.resolver_schema_int2, self.resolver_schema_ext)) 
492          schema_doc = etree.parse(self.resolver_schema_int, parser = parser) 
493          schema = etree.XMLSchema(schema_doc) 
494   
495   
503   
504   
505  if __name__ == '__main__': 
506      print('to test use test.py %s' % __file__) 
507