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 -class ETreeXMLSchemaTestCase(HelperTestCase):
     17 -    def test_xmlschema(self):
     18          tree_valid = self.parse('<a><b></b></a>')
     19          tree_invalid = self.parse('<a><c></c></a>')
     20          schema = self.parse('''
     21  <xsd:schema xmlns:xsd="http://www.w3.org/2001/XMLSchema">
     22    <xsd:element name="a" type="AType"/>
     23    <xsd:complexType name="AType">
     24      <xsd:sequence>
     25        <xsd:element name="b" type="xsd:string" />
     26      </xsd:sequence>
     27    </xsd:complexType>
     28  </xsd:schema>
     29  ''')
     30          schema = etree.XMLSchema(schema)
     31          self.assertTrue(schema.validate(tree_valid))
     32          self.assertTrue(not schema.validate(tree_invalid))
     33
     34 -    def test_xmlschema_default_attributes(self):
     35          schema = self.parse('''
     36  <xsd:schema xmlns:xsd="http://www.w3.org/2001/XMLSchema">
     37    <xsd:element name="a" type="AType"/>
     38    <xsd:complexType name="AType">
     39      <xsd:sequence minOccurs="4" maxOccurs="4">
     40        <xsd:element name="b" type="BType" />
     41      </xsd:sequence>
     42    </xsd:complexType>
     43    <xsd:complexType name="BType">
     44      <xsd:attribute name="hardy" type="xsd:string" default="hey" />
     45    </xsd:complexType>
     46  </xsd:schema>
     47  ''')
     48          schema = etree.XMLSchema(schema, attribute_defaults=True)
     49
     50          tree = self.parse('<a><b hardy="ho"/><b/><b hardy="ho"/><b/></a>')
     51
     52          root = tree.getroot()
     53          self.assertEqual('ho', root[0].get('hardy'))
     54          self.assertEqual(None, root[1].get('hardy'))
     55          self.assertEqual('ho', root[2].get('hardy'))
     56          self.assertEqual(None, root[3].get('hardy'))
     57
     58          self.assertTrue(schema(tree))
     59
     60          root = tree.getroot()
     61          self.assertEqual('ho', root[0].get('hardy'))
     62          self.assertEqual('hey', root[1].get('hardy'))
     63          self.assertEqual('ho', root[2].get('hardy'))
     64          self.assertEqual('hey', root[3].get('hardy'))
     65
     66 -    def test_xmlschema_parse(self):
     67          schema = self.parse('''
     68  <xsd:schema xmlns:xsd="http://www.w3.org/2001/XMLSchema">
     69    <xsd:element name="a" type="AType"/>
     70    <xsd:complexType name="AType">
     71      <xsd:sequence>
     72        <xsd:element name="b" type="xsd:string" />
     73      </xsd:sequence>
     74    </xsd:complexType>
     75  </xsd:schema>
     76  ''')
     77          schema = etree.XMLSchema(schema)
     78          parser = etree.XMLParser(schema=schema)
     79
     80          tree_valid = self.parse('<a><b></b></a>', parser=parser)
     81          self.assertEqual('a', tree_valid.getroot().tag)
     82
     83          self.assertRaises(etree.XMLSyntaxError,
     84                            self.parse, '<a><c></c></a>', parser=parser)
     85
     86 -    def test_xmlschema_parse_default_attributes(self):
     87          # does not work as of libxml2 2.7.3
     88          schema = self.parse('''
     89  <xsd:schema xmlns:xsd="http://www.w3.org/2001/XMLSchema">
     90    <xsd:element name="a" type="AType"/>
     91    <xsd:complexType name="AType">
     92      <xsd:sequence minOccurs="4" maxOccurs="4">
     93        <xsd:element name="b" type="BType" />
     94      </xsd:sequence>
     95    </xsd:complexType>
     96    <xsd:complexType name="BType">
     97      <xsd:attribute name="hardy" type="xsd:string" default="hey" />
     98    </xsd:complexType>
     99  </xsd:schema>
    100  ''')
    101          schema = etree.XMLSchema(schema)
    102          parser = etree.XMLParser(schema=schema, attribute_defaults=True)
    103
    104          tree_valid = self.parse('<a><b hardy="ho"/><b/><b hardy="ho"/><b/></a>',
    105                                  parser=parser)
    106          root = tree_valid.getroot()
    107          self.assertEqual('ho', root[0].get('hardy'))
    108          self.assertEqual('hey', root[1].get('hardy'))
    109          self.assertEqual('ho', root[2].get('hardy'))
    110          self.assertEqual('hey', root[3].get('hardy'))
    111
    112 -    def test_xmlschema_parse_default_attributes_schema_config(self):
    113          # does not work as of libxml2 2.7.3
    114          schema = self.parse('''
    115  <xsd:schema xmlns:xsd="http://www.w3.org/2001/XMLSchema">
    116    <xsd:element name="a" type="AType"/>
    117    <xsd:complexType name="AType">
    118      <xsd:sequence minOccurs="4" maxOccurs="4">
    119        <xsd:element name="b" type="BType" />
    120      </xsd:sequence>
    121    </xsd:complexType>
    122    <xsd:complexType name="BType">
    123      <xsd:attribute name="hardy" type="xsd:string" default="hey" />
    124    </xsd:complexType>
    125  </xsd:schema>
    126  ''')
    127          schema = etree.XMLSchema(schema, attribute_defaults=True)
    128          parser = etree.XMLParser(schema=schema)
    129
    130          tree_valid = self.parse('<a><b hardy="ho"/><b/><b hardy="ho"/><b/></a>',
    131                                  parser=parser)
    132          root = tree_valid.getroot()
    133          self.assertEqual('ho', root[0].get('hardy'))
    134          self.assertEqual('hey', root[1].get('hardy'))
    135          self.assertEqual('ho', root[2].get('hardy'))
    136          self.assertEqual('hey', root[3].get('hardy'))
    137
    138 -    def test_xmlschema_parse_fixed_attributes(self):
    139          # does not work as of libxml2 2.7.3
    140          schema = self.parse('''
    141  <xsd:schema xmlns:xsd="http://www.w3.org/2001/XMLSchema">
    142    <xsd:element name="a" type="AType"/>
    143    <xsd:complexType name="AType">
    144      <xsd:sequence minOccurs="3" maxOccurs="3">
    145        <xsd:element name="b" type="BType" />
    146      </xsd:sequence>
    147    </xsd:complexType>
    148    <xsd:complexType name="BType">
    149      <xsd:attribute name="hardy" type="xsd:string" fixed="hey" />
    150    </xsd:complexType>
    151  </xsd:schema>
    152  ''')
    153          schema = etree.XMLSchema(schema)
    154          parser = etree.XMLParser(schema=schema, attribute_defaults=True)
    155
    156          tree_valid = self.parse('<a><b/><b hardy="hey"/><b/></a>',
    157                                  parser=parser)
    158          root = tree_valid.getroot()
    159          self.assertEqual('hey', root[0].get('hardy'))
    160          self.assertEqual('hey', root[1].get('hardy'))
    161          self.assertEqual('hey', root[2].get('hardy'))
    162
    163 -    def test_xmlschema_stringio(self):
    164          schema_file = BytesIO('''
    165  <xsd:schema xmlns:xsd="http://www.w3.org/2001/XMLSchema">
    166    <xsd:element name="a" type="AType"/>
    167    <xsd:complexType name="AType">
    168      <xsd:sequence>
    169        <xsd:element name="b" type="xsd:string" />
    170      </xsd:sequence>
    171    </xsd:complexType>
    172  </xsd:schema>
    173  ''')
    174          schema = etree.XMLSchema(file=schema_file)
    175          parser = etree.XMLParser(schema=schema)
    176
    177          tree_valid = self.parse('<a><b></b></a>', parser=parser)
    178          self.assertEqual('a', tree_valid.getroot().tag)
    179
    180          self.assertRaises(etree.XMLSyntaxError,
    181                            self.parse, '<a><c></c></a>', parser=parser)
    182
    183 -    def test_xmlschema_iterparse(self):
    184          schema = self.parse('''
    185  <xsd:schema xmlns:xsd="http://www.w3.org/2001/XMLSchema">
    186    <xsd:element name="a" type="AType"/>
    187    <xsd:complexType name="AType">
    188      <xsd:sequence>
    189        <xsd:element name="b" type="xsd:string" />
    190      </xsd:sequence>
    191    </xsd:complexType>
    192  </xsd:schema>
    193  ''')
    194          schema = etree.XMLSchema(schema)
    195          xml = BytesIO('<a><b></b></a>')
    196          events = [ (event, el.tag)
    197                     for (event, el) in etree.iterparse(xml, schema=schema) ]
    198
    199          self.assertEqual([('end', 'b'), ('end', 'a')],
    200                            events)
    201
    202 -    def test_xmlschema_iterparse_fail(self):
    203          schema = self.parse('''
    204  <xsd:schema xmlns:xsd="http://www.w3.org/2001/XMLSchema">
    205    <xsd:element name="a" type="AType"/>
    206    <xsd:complexType name="AType">
    207      <xsd:sequence>
    208        <xsd:element name="b" type="xsd:string" />
    209      </xsd:sequence>
    210    </xsd:complexType>
    211  </xsd:schema>
    212  ''')
    213          schema = etree.XMLSchema(schema)
    214          self.assertRaises(
    215              etree.XMLSyntaxError,
    216              list, etree.iterparse(BytesIO('<a><c></c></a>'), schema=schema))
    217
    218 -    def test_xmlschema_elementtree_error(self):
    219          self.assertRaises(ValueError, etree.XMLSchema, etree.ElementTree())
    220
    221 -    def test_xmlschema_invalid_schema1(self):
    222          schema = self.parse('''\
    223  <xsd:schema xmlns:xsd="http://www.w3.org/2001/XMLSchema">
    224    <element name="a" type="AType"/>
    225    <xsd:complexType name="AType">
    226      <xsd:sequence>
    227        <xsd:element name="b" type="xsd:string" />
    228      </xsd:sequence>
    229    </xsd:complexType>
    230  </xsd:schema>
    231  ''')
    232          self.assertRaises(etree.XMLSchemaParseError,
    233                            etree.XMLSchema, schema)
    234
    235 -    def test_xmlschema_invalid_schema2(self):
    236          schema = self.parse('<test/>')
    237          self.assertRaises(etree.XMLSchemaParseError,
    238                            etree.XMLSchema, schema)
    239
    240 -    def test_xmlschema_file(self):
    241          # this will only work if we access the file through path or
    242          # file object..
    243          f = open(fileInTestDir('test.xsd'), 'rb')
    244          try:
    245              schema = etree.XMLSchema(file=f)
    246          finally:
    247              f.close()
    248          tree_valid = self.parse('<a><b></b></a>')
    249          self.assertTrue(schema.validate(tree_valid))
    250
    251 -    def test_xmlschema_import_file(self):
    252          # this will only work if we access the file through path or
    253          # file object..
    254          schema = etree.XMLSchema(file=fileInTestDir('test_import.xsd'))
    255          tree_valid = self.parse(
    256              '<a:x xmlns:a="http://codespeak.net/lxml/schema/ns1"><b></b></a:x>')
    257          self.assertTrue(schema.validate(tree_valid))
    258
    259 -    def test_xmlschema_shortcut(self):
    260          tree_valid = self.parse('<a><b></b></a>')
    261          tree_invalid = self.parse('<a><c></c></a>')
    262          schema = self.parse('''\
    263  <xsd:schema xmlns:xsd="http://www.w3.org/2001/XMLSchema">
    264    <xsd:element name="a" type="AType"/>
    265    <xsd:complexType name="AType">
    266      <xsd:sequence>
    267        <xsd:element name="b" type="xsd:string" />
    268      </xsd:sequence>
    269    </xsd:complexType>
    270  </xsd:schema>
    271  ''')
    272          self.assertTrue(tree_valid.xmlschema(schema))
    273          self.assertTrue(not tree_invalid.xmlschema(schema))
    274
    275
    276 -class ETreeXMLSchemaResolversTestCase(HelperTestCase):
    277      resolver_schema_int = BytesIO("""\
    278  <xsd:schema xmlns:xsd="http://www.w3.org/2001/XMLSchema"
    279      xmlns:etype="http://codespeak.net/lxml/test/external"
    280      targetNamespace="http://codespeak.net/lxml/test/internal">
    281          <xsd:import namespace="http://codespeak.net/lxml/test/external" schemaLocation="XXX.xsd" />
    282          <xsd:element name="a" type="etype:AType"/>
    283  </xsd:schema>""")
    284
    285      resolver_schema_int2 = BytesIO("""\
    286  <xsd:schema xmlns:xsd="http://www.w3.org/2001/XMLSchema"
    287      xmlns:etype="http://codespeak.net/lxml/test/external"
    288      targetNamespace="http://codespeak.net/lxml/test/internal">
    289          <xsd:import namespace="http://codespeak.net/lxml/test/external" schemaLocation="YYY.xsd" />
    290          <xsd:element name="a" type="etype:AType"/>
    291  </xsd:schema>""")
    292
    293      resolver_schema_ext = """\
    294  <xsd:schema xmlns:xsd="http://www.w3.org/2001/XMLSchema"
    295      targetNamespace="http://codespeak.net/lxml/test/external">
    296      <xsd:complexType name="AType">
    297        <xsd:sequence><xsd:element name="b" type="xsd:string" minOccurs="0" maxOccurs="unbounded" /></xsd:sequence>
    298      </xsd:complexType>
    299  </xsd:schema>"""
    300
    301 -    class simple_resolver(etree.Resolver):
    302 -        def __init__(self, schema):
    303              self.schema = schema
    304
    305 -        def resolve(self, url, id, context):
    306              assert url == 'XXX.xsd'
    307              return self.resolve_string(self.schema, context)
    308
    309      # tests:
    310
    311 -    def test_xmlschema_resolvers(self):
    312          # test that resolvers work with schema.
    313          parser = etree.XMLParser()
    314          parser.resolvers.add(self.simple_resolver(self.resolver_schema_ext))
    315          schema_doc = etree.parse(self.resolver_schema_int, parser = parser)
    316          schema = etree.XMLSchema(schema_doc)
    317
    318 -    def test_xmlschema_resolvers_root(self):
    319          # test that the default resolver will get called if there's no
    320          # specific parser resolver.
    321          root_resolver = self.simple_resolver(self.resolver_schema_ext)
    322          etree.get_default_parser().resolvers.add(root_resolver)
    323          schema_doc = etree.parse(self.resolver_schema_int)
    324          schema = etree.XMLSchema(schema_doc)
    325          etree.get_default_parser().resolvers.remove(root_resolver)
    326
    327 -    def test_xmlschema_resolvers_noroot(self):
    328          # test that the default resolver will not get called when a
    329          # more specific resolver is registered.
    330
    331          class res_root(etree.Resolver):
    332              def resolve(self, url, id, context):
    333                  assert False
    334                  return None
    335
    336          root_resolver = res_root()
    337          etree.get_default_parser().resolvers.add(root_resolver)
    338
    339          parser = etree.XMLParser()
    340          parser.resolvers.add(self.simple_resolver(self.resolver_schema_ext))
    341
    342          schema_doc = etree.parse(self.resolver_schema_int, parser = parser)
    343          schema = etree.XMLSchema(schema_doc)
    344          etree.get_default_parser().resolvers.remove(root_resolver)
    345
    346 -    def test_xmlschema_nested_resolvers(self):
    347          # test that resolvers work in a nested fashion.
    348
    349          resolver_schema = self.resolver_schema_ext
    350
    351          class res_nested(etree.Resolver):
    352              def __init__(self, ext_schema):
    353                  self.ext_schema = ext_schema
    354
    355              def resolve(self, url, id, context):
    356                  assert url == 'YYY.xsd'
    357                  return self.resolve_string(self.ext_schema, context)
    358
    359          class res(etree.Resolver):
    360              def __init__(self, ext_schema_1, ext_schema_2):
    361                  self.ext_schema_1 = ext_schema_1
    362                  self.ext_schema_2 = ext_schema_2
    363
    364              def resolve(self, url, id, context):
    365                  assert url == 'XXX.xsd'
    366
    367                  new_parser = etree.XMLParser()
    368                  new_parser.resolvers.add(res_nested(self.ext_schema_2))
    369                  new_schema_doc = etree.parse(self.ext_schema_1, parser = new_parser)
    370                  new_schema = etree.XMLSchema(new_schema_doc)
    371
    372                  return self.resolve_string(resolver_schema, context)
    373
    374          parser = etree.XMLParser()
    375          parser.resolvers.add(res(self.resolver_schema_int2, self.resolver_schema_ext))
    376          schema_doc = etree.parse(self.resolver_schema_int, parser = parser)
    377          schema = etree.XMLSchema(schema_doc)
    378
    379 -def test_suite():
    380      suite = unittest.TestSuite()
    381      suite.addTests([unittest.makeSuite(ETreeXMLSchemaTestCase)])
    382      suite.addTests([unittest.makeSuite(ETreeXMLSchemaResolversTestCase)])
    383      suite.addTests(
    384          [make_doctest('../../../doc/validation.txt')])
    385      return suite
    386
    387  if __name__ == '__main__':
    388      print('to test use test.py %s' % __file__)
    389