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.assertTrue(not schema.validate(tree_invalid))
34
36 schema = self.parse('''
37 <xsd:schema xmlns:xsd="http://www.w3.org/2001/XMLSchema">
38 <xsd:element name="a" type="AType"/>
39 <xsd:complexType name="AType">
40 <xsd:sequence minOccurs="4" maxOccurs="4">
41 <xsd:element name="b" type="BType" />
42 </xsd:sequence>
43 </xsd:complexType>
44 <xsd:complexType name="BType">
45 <xsd:attribute name="hardy" type="xsd:string" default="hey" />
46 </xsd:complexType>
47 </xsd:schema>
48 ''')
49 schema = etree.XMLSchema(schema, attribute_defaults=True)
50
51 tree = self.parse('<a><b hardy="ho"/><b/><b hardy="ho"/><b/></a>')
52
53 root = tree.getroot()
54 self.assertEqual('ho', root[0].get('hardy'))
55 self.assertEqual(None, root[1].get('hardy'))
56 self.assertEqual('ho', root[2].get('hardy'))
57 self.assertEqual(None, root[3].get('hardy'))
58
59 self.assertTrue(schema(tree))
60
61 root = tree.getroot()
62 self.assertEqual('ho', root[0].get('hardy'))
63 self.assertEqual('hey', root[1].get('hardy'))
64 self.assertEqual('ho', root[2].get('hardy'))
65 self.assertEqual('hey', root[3].get('hardy'))
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>
73 <xsd:element name="b" type="xsd:string" />
74 </xsd:sequence>
75 </xsd:complexType>
76 </xsd:schema>
77 ''')
78 schema = etree.XMLSchema(schema)
79 parser = etree.XMLParser(schema=schema)
80
81 tree_valid = self.parse('<a><b></b></a>', parser=parser)
82 self.assertEqual('a', tree_valid.getroot().tag)
83
84 self.assertRaises(etree.XMLSyntaxError,
85 self.parse, '<a><c></c></a>', parser=parser)
86
88
89 schema = self.parse('''
90 <xsd:schema xmlns:xsd="http://www.w3.org/2001/XMLSchema">
91 <xsd:element name="a" type="AType"/>
92 <xsd:complexType name="AType">
93 <xsd:sequence minOccurs="4" maxOccurs="4">
94 <xsd:element name="b" type="BType" />
95 </xsd:sequence>
96 </xsd:complexType>
97 <xsd:complexType name="BType">
98 <xsd:attribute name="hardy" type="xsd:string" default="hey" />
99 </xsd:complexType>
100 </xsd:schema>
101 ''')
102 schema = etree.XMLSchema(schema)
103 parser = etree.XMLParser(schema=schema, attribute_defaults=True)
104
105 tree_valid = self.parse('<a><b hardy="ho"/><b/><b hardy="ho"/><b/></a>',
106 parser=parser)
107 root = tree_valid.getroot()
108 self.assertEqual('ho', root[0].get('hardy'))
109 self.assertEqual('hey', root[1].get('hardy'))
110 self.assertEqual('ho', root[2].get('hardy'))
111 self.assertEqual('hey', root[3].get('hardy'))
112
114
115 schema = self.parse('''
116 <xsd:schema xmlns:xsd="http://www.w3.org/2001/XMLSchema">
117 <xsd:element name="a" type="AType"/>
118 <xsd:complexType name="AType">
119 <xsd:sequence minOccurs="4" maxOccurs="4">
120 <xsd:element name="b" type="BType" />
121 </xsd:sequence>
122 </xsd:complexType>
123 <xsd:complexType name="BType">
124 <xsd:attribute name="hardy" type="xsd:string" default="hey" />
125 </xsd:complexType>
126 </xsd:schema>
127 ''')
128 schema = etree.XMLSchema(schema, attribute_defaults=True)
129 parser = etree.XMLParser(schema=schema)
130
131 tree_valid = self.parse('<a><b hardy="ho"/><b/><b hardy="ho"/><b/></a>',
132 parser=parser)
133 root = tree_valid.getroot()
134 self.assertEqual('ho', root[0].get('hardy'))
135 self.assertEqual('hey', root[1].get('hardy'))
136 self.assertEqual('ho', root[2].get('hardy'))
137 self.assertEqual('hey', root[3].get('hardy'))
138
140
141 schema = self.parse('''
142 <xsd:schema xmlns:xsd="http://www.w3.org/2001/XMLSchema">
143 <xsd:element name="a" type="AType"/>
144 <xsd:complexType name="AType">
145 <xsd:sequence minOccurs="3" maxOccurs="3">
146 <xsd:element name="b" type="BType" />
147 </xsd:sequence>
148 </xsd:complexType>
149 <xsd:complexType name="BType">
150 <xsd:attribute name="hardy" type="xsd:string" fixed="hey" />
151 </xsd:complexType>
152 </xsd:schema>
153 ''')
154 schema = etree.XMLSchema(schema)
155 parser = etree.XMLParser(schema=schema, attribute_defaults=True)
156
157 tree_valid = self.parse('<a><b/><b hardy="hey"/><b/></a>',
158 parser=parser)
159 root = tree_valid.getroot()
160 self.assertEqual('hey', root[0].get('hardy'))
161 self.assertEqual('hey', root[1].get('hardy'))
162 self.assertEqual('hey', root[2].get('hardy'))
163
165 schema_file = BytesIO('''
166 <xsd:schema xmlns:xsd="http://www.w3.org/2001/XMLSchema">
167 <xsd:element name="a" type="AType"/>
168 <xsd:complexType name="AType">
169 <xsd:sequence>
170 <xsd:element name="b" type="xsd:string" />
171 </xsd:sequence>
172 </xsd:complexType>
173 </xsd:schema>
174 ''')
175 schema = etree.XMLSchema(file=schema_file)
176 parser = etree.XMLParser(schema=schema)
177
178 tree_valid = self.parse('<a><b></b></a>', parser=parser)
179 self.assertEqual('a', tree_valid.getroot().tag)
180
181 self.assertRaises(etree.XMLSyntaxError,
182 self.parse, '<a><c></c></a>', parser=parser)
183
185 schema = self.parse('''
186 <xsd:schema xmlns:xsd="http://www.w3.org/2001/XMLSchema">
187 <xsd:element name="a" type="AType"/>
188 <xsd:complexType name="AType">
189 <xsd:sequence>
190 <xsd:element name="b" type="xsd:string" />
191 </xsd:sequence>
192 </xsd:complexType>
193 </xsd:schema>
194 ''')
195 schema = etree.XMLSchema(schema)
196 xml = BytesIO('<a><b></b></a>')
197 events = [ (event, el.tag)
198 for (event, el) in etree.iterparse(xml, schema=schema) ]
199
200 self.assertEqual([('end', 'b'), ('end', 'a')],
201 events)
202
204 schema = self.parse('''
205 <xsd:schema xmlns:xsd="http://www.w3.org/2001/XMLSchema">
206 <xsd:element name="a" type="AType"/>
207 <xsd:complexType name="AType">
208 <xsd:sequence>
209 <xsd:element name="b" type="xsd:string" />
210 </xsd:sequence>
211 </xsd:complexType>
212 </xsd:schema>
213 ''')
214 schema = etree.XMLSchema(schema)
215 self.assertRaises(
216 etree.XMLSyntaxError,
217 list, etree.iterparse(BytesIO('<a><c></c></a>'), schema=schema))
218
221
224
226 schema = self.parse('''
227 <xsd:schema xmlns:xsd="http://www.w3.org/2001/XMLSchema">
228 <xsd:element name="a" type="xsd:string"/>
229 </xsd:schema>
230 ''')
231 schema = etree.XMLSchema(schema)
232
233 root = etree.Element('a')
234 root.text = 'TEST'
235 self.assertTrue(schema(root))
236
237 self.assertRaises(ValueError, schema, etree.Comment('TEST'))
238 self.assertRaises(ValueError, schema, etree.PI('a', 'text'))
239 self.assertRaises(ValueError, schema, etree.Entity('text'))
240
242 schema = self.parse('''\
243 <xsd:schema xmlns:xsd="http://www.w3.org/2001/XMLSchema">
244 <element name="a" type="AType"/>
245 <xsd:complexType name="AType">
246 <xsd:sequence>
247 <xsd:element name="b" type="xsd:string" />
248 </xsd:sequence>
249 </xsd:complexType>
250 </xsd:schema>
251 ''')
252 self.assertRaises(etree.XMLSchemaParseError,
253 etree.XMLSchema, schema)
254
259
270
272
273
274 schema = etree.XMLSchema(file=fileInTestDir('test_import.xsd'))
275 tree_valid = self.parse(
276 '<a:x xmlns:a="http://codespeak.net/lxml/schema/ns1"><b></b></a:x>')
277 self.assertTrue(schema.validate(tree_valid))
278
280 tree_valid = self.parse('<a><b></b></a>')
281 tree_invalid = self.parse('<a><c></c></a>')
282 schema = self.parse('''\
283 <xsd:schema xmlns:xsd="http://www.w3.org/2001/XMLSchema">
284 <xsd:element name="a" type="AType"/>
285 <xsd:complexType name="AType">
286 <xsd:sequence>
287 <xsd:element name="b" type="xsd:string" />
288 </xsd:sequence>
289 </xsd:complexType>
290 </xsd:schema>
291 ''')
292 self.assertTrue(tree_valid.xmlschema(schema))
293 self.assertTrue(not tree_invalid.xmlschema(schema))
294
295
297 resolver_schema_int = BytesIO("""\
298 <xsd:schema xmlns:xsd="http://www.w3.org/2001/XMLSchema"
299 xmlns:etype="http://codespeak.net/lxml/test/external"
300 targetNamespace="http://codespeak.net/lxml/test/internal">
301 <xsd:import namespace="http://codespeak.net/lxml/test/external" schemaLocation="XXX.xsd" />
302 <xsd:element name="a" type="etype:AType"/>
303 </xsd:schema>""")
304
305 resolver_schema_int2 = BytesIO("""\
306 <xsd:schema xmlns:xsd="http://www.w3.org/2001/XMLSchema"
307 xmlns:etype="http://codespeak.net/lxml/test/external"
308 targetNamespace="http://codespeak.net/lxml/test/internal">
309 <xsd:import namespace="http://codespeak.net/lxml/test/external" schemaLocation="YYY.xsd" />
310 <xsd:element name="a" type="etype:AType"/>
311 </xsd:schema>""")
312
313 resolver_schema_ext = """\
314 <xsd:schema xmlns:xsd="http://www.w3.org/2001/XMLSchema"
315 targetNamespace="http://codespeak.net/lxml/test/external">
316 <xsd:complexType name="AType">
317 <xsd:sequence><xsd:element name="b" type="xsd:string" minOccurs="0" maxOccurs="unbounded" /></xsd:sequence>
318 </xsd:complexType>
319 </xsd:schema>"""
320
324
325 - def resolve(self, url, id, context):
326 assert url == 'XXX.xsd'
327 return self.resolve_string(self.schema, context)
328
329
330
337
346
348
349
350
351 class res_root(etree.Resolver):
352 def resolve(self, url, id, context):
353 assert False
354 return None
355
356 root_resolver = res_root()
357 etree.get_default_parser().resolvers.add(root_resolver)
358
359 parser = etree.XMLParser()
360 parser.resolvers.add(self.simple_resolver(self.resolver_schema_ext))
361
362 schema_doc = etree.parse(self.resolver_schema_int, parser = parser)
363 schema = etree.XMLSchema(schema_doc)
364 etree.get_default_parser().resolvers.remove(root_resolver)
365
367
368
369 resolver_schema = self.resolver_schema_ext
370
371 class res_nested(etree.Resolver):
372 def __init__(self, ext_schema):
373 self.ext_schema = ext_schema
374
375 def resolve(self, url, id, context):
376 assert url == 'YYY.xsd'
377 return self.resolve_string(self.ext_schema, context)
378
379 class res(etree.Resolver):
380 def __init__(self, ext_schema_1, ext_schema_2):
381 self.ext_schema_1 = ext_schema_1
382 self.ext_schema_2 = ext_schema_2
383
384 def resolve(self, url, id, context):
385 assert url == 'XXX.xsd'
386
387 new_parser = etree.XMLParser()
388 new_parser.resolvers.add(res_nested(self.ext_schema_2))
389 new_schema_doc = etree.parse(self.ext_schema_1, parser = new_parser)
390 new_schema = etree.XMLSchema(new_schema_doc)
391
392 return self.resolve_string(resolver_schema, context)
393
394 parser = etree.XMLParser()
395 parser.resolvers.add(res(self.resolver_schema_int2, self.resolver_schema_ext))
396 schema_doc = etree.parse(self.resolver_schema_int, parser = parser)
397 schema = etree.XMLSchema(schema_doc)
398
399
407
408
409 if __name__ == '__main__':
410 print('to test use test.py %s' % __file__)
411