Package lxml :: Package tests :: Module test_xmlschema

[hide private]
[frames] | no frames]

# Source Code for Module lxml.tests.test_xmlschema

      1  # -*- coding: utf-8 -*-
      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) # needed for Py3
     12
     13  from common_imports import etree, BytesIO, HelperTestCase, fileInTestDir
     14  from common_imports import doctest, make_doctest
     15
     16
     17 -class ETreeXMLSchemaTestCase(HelperTestCase):
     18 -    def test_xmlschema(self):
     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))     # retry valid
     35          self.assertFalse(schema.validate(tree_invalid))  # retry invalid
     36
     37 -    def test_xmlschema_error_log(self):
     38          tree_valid = self.parse('<a><b></b></a>')
     39          tree_invalid = self.parse('<a><c></c></a>')
     40          schema = self.parse('''
     41  <xsd:schema xmlns:xsd="http://www.w3.org/2001/XMLSchema">
     42    <xsd:element name="a" type="AType"/>
     43    <xsd:complexType name="AType">
     44      <xsd:sequence>
     45        <xsd:element name="b" type="xsd:string" />
     46      </xsd:sequence>
     47    </xsd:complexType>
     48  </xsd:schema>
     49  ''')
     50          schema = etree.XMLSchema(schema)
     51          self.assertTrue(schema.validate(tree_valid))
     52          self.assertFalse(schema.error_log.filter_from_errors())
     53
     54          self.assertFalse(schema.validate(tree_invalid))
     55          self.assertTrue(schema.error_log.filter_from_errors())
     56          self.assertTrue(schema.error_log.filter_types(
     57              etree.ErrorTypes.SCHEMAV_ELEMENT_CONTENT))
     58
     59          self.assertTrue(schema.validate(tree_valid))
     60          self.assertFalse(schema.error_log.filter_from_errors())
     61
     62          self.assertFalse(schema.validate(tree_invalid))
     63          self.assertTrue(schema.error_log.filter_from_errors())
     64          self.assertTrue(schema.error_log.filter_types(
     65              etree.ErrorTypes.SCHEMAV_ELEMENT_CONTENT))
     66
     67 -    def test_xmlschema_default_attributes(self):
     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
     99 -    def test_xmlschema_parse(self):
    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
    119 -    def test_xmlschema_parse_default_attributes(self):
    120          # does not work as of libxml2 2.7.3
    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
    145 -    def test_xmlschema_parse_default_attributes_schema_config(self):
    146          # does not work as of libxml2 2.7.3
    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
    171 -    def test_xmlschema_parse_fixed_attributes(self):
    172          # does not work as of libxml2 2.7.3
    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
    196 -    def test_xmlschema_stringio(self):
    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
    216 -    def test_xmlschema_iterparse(self):
    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
    235 -    def test_xmlschema_iterparse_fail(self):
    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
    251 -    def test_xmlschema_elementtree_error(self):
    252          self.assertRaises(ValueError, etree.XMLSchema, etree.ElementTree())
    253
    254 -    def test_xmlschema_comment_error(self):
    255          self.assertRaises(ValueError, etree.XMLSchema, etree.Comment('TEST'))
    256
    257 -    def test_xmlschema_illegal_validation_error(self):
    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
    273 -    def test_xmlschema_invalid_schema1(self):
    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
    287 -    def test_xmlschema_invalid_schema2(self):
    288          schema = self.parse('<test/>')
    289          self.assertRaises(etree.XMLSchemaParseError,
    290                            etree.XMLSchema, schema)
    291
    292 -    def test_xmlschema_file(self):
    293          # this will only work if we access the file through path or
    294          # file object..
    295          f = open(fileInTestDir('test.xsd'), 'rb')
    296          try:
    297              schema = etree.XMLSchema(file=f)
    298          finally:
    299              f.close()
    300          tree_valid = self.parse('<a><b></b></a>')
    301          self.assertTrue(schema.validate(tree_valid))
    302
    303 -    def test_xmlschema_import_file(self):
    304          # this will only work if we access the file through path or
    305          # file object..
    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
    311 -    def test_xmlschema_shortcut(self):
    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
    327
    328 -class ETreeXMLSchemaResolversTestCase(HelperTestCase):
    329      resolver_schema_int = BytesIO("""\
    330  <xsd:schema xmlns:xsd="http://www.w3.org/2001/XMLSchema"
    331      xmlns:etype="http://codespeak.net/lxml/test/external"
    332      targetNamespace="http://codespeak.net/lxml/test/internal">
    333          <xsd:import namespace="http://codespeak.net/lxml/test/external" schemaLocation="XXX.xsd" />
    334          <xsd:element name="a" type="etype:AType"/>
    335  </xsd:schema>""")
    336
    337      resolver_schema_int2 = BytesIO("""\
    338  <xsd:schema xmlns:xsd="http://www.w3.org/2001/XMLSchema"
    339      xmlns:etype="http://codespeak.net/lxml/test/external"
    340      targetNamespace="http://codespeak.net/lxml/test/internal">
    341          <xsd:import namespace="http://codespeak.net/lxml/test/external" schemaLocation="YYY.xsd" />
    342          <xsd:element name="a" type="etype:AType"/>
    343  </xsd:schema>""")
    344
    345      resolver_schema_ext = """\
    346  <xsd:schema xmlns:xsd="http://www.w3.org/2001/XMLSchema"
    347      targetNamespace="http://codespeak.net/lxml/test/external">
    348      <xsd:complexType name="AType">
    349        <xsd:sequence><xsd:element name="b" type="xsd:string" minOccurs="0" maxOccurs="unbounded" /></xsd:sequence>
    350      </xsd:complexType>
    351  </xsd:schema>"""
    352
    353 -    class simple_resolver(etree.Resolver):
    354 -        def __init__(self, schema):
    355              self.schema = schema
    356
    357 -        def resolve(self, url, id, context):
    358              assert url == 'XXX.xsd'
    359              return self.resolve_string(self.schema, context)
    360
    361      # tests:
    362
    363 -    def test_xmlschema_resolvers(self):
    364          # test that resolvers work with schema.
    365          parser = etree.XMLParser()
    366          parser.resolvers.add(self.simple_resolver(self.resolver_schema_ext))
    367          schema_doc = etree.parse(self.resolver_schema_int, parser = parser)
    368          schema = etree.XMLSchema(schema_doc)
    369
    370 -    def test_xmlschema_resolvers_root(self):
    371          # test that the default resolver will get called if there's no
    372          # specific parser resolver.
    373          root_resolver = self.simple_resolver(self.resolver_schema_ext)
    374          etree.get_default_parser().resolvers.add(root_resolver)
    375          schema_doc = etree.parse(self.resolver_schema_int)
    376          schema = etree.XMLSchema(schema_doc)
    377          etree.get_default_parser().resolvers.remove(root_resolver)
    378
    379 -    def test_xmlschema_resolvers_noroot(self):
    380          # test that the default resolver will not get called when a
    381          # more specific resolver is registered.
    382
    383          class res_root(etree.Resolver):
    384              def resolve(self, url, id, context):
    385                  assert False
    386                  return None
    387
    388          root_resolver = res_root()
    389          etree.get_default_parser().resolvers.add(root_resolver)
    390
    391          parser = etree.XMLParser()
    392          parser.resolvers.add(self.simple_resolver(self.resolver_schema_ext))
    393
    394          schema_doc = etree.parse(self.resolver_schema_int, parser = parser)
    395          schema = etree.XMLSchema(schema_doc)
    396          etree.get_default_parser().resolvers.remove(root_resolver)
    397
    398 -    def test_xmlschema_nested_resolvers(self):
    399          # test that resolvers work in a nested fashion.
    400
    401          resolver_schema = self.resolver_schema_ext
    402
    403          class res_nested(etree.Resolver):
    404              def __init__(self, ext_schema):
    405                  self.ext_schema = ext_schema
    406
    407              def resolve(self, url, id, context):
    408                  assert url == 'YYY.xsd'
    409                  return self.resolve_string(self.ext_schema, context)
    410
    411          class res(etree.Resolver):
    412              def __init__(self, ext_schema_1, ext_schema_2):
    413                  self.ext_schema_1 = ext_schema_1
    414                  self.ext_schema_2 = ext_schema_2
    415
    416              def resolve(self, url, id, context):
    417                  assert url == 'XXX.xsd'
    418
    419                  new_parser = etree.XMLParser()
    420                  new_parser.resolvers.add(res_nested(self.ext_schema_2))
    421                  new_schema_doc = etree.parse(self.ext_schema_1, parser = new_parser)
    422                  new_schema = etree.XMLSchema(new_schema_doc)
    423
    424                  return self.resolve_string(resolver_schema, context)
    425
    426          parser = etree.XMLParser()
    427          parser.resolvers.add(res(self.resolver_schema_int2, self.resolver_schema_ext))
    428          schema_doc = etree.parse(self.resolver_schema_int, parser = parser)
    429          schema = etree.XMLSchema(schema_doc)
    430
    431
    432 -def test_suite():
    433      suite = unittest.TestSuite()
    434      suite.addTests([unittest.makeSuite(ETreeXMLSchemaTestCase)])
    435      suite.addTests([unittest.makeSuite(ETreeXMLSchemaResolversTestCase)])
    436      suite.addTests(
    437          [make_doctest('../../../doc/validation.txt')])
    438      return suite
    439
    440
    441  if __name__ == '__main__':
    442      print('to test use test.py %s' % __file__)
    443