lxml.tests.test_xmlschema
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 )
390
391
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