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