Table Of Contents

Previous topic

SIMO package structure

Next topic

operationmapping.py

This Page

xmlobject.py

class XmlObject(object):

Base class for SIMO XML definitions has two properties: xml and schema. The typedef schema will be included into the schema document if the schema has an include-element. When the schema is set, a parser is generated which is used to parse and validate the xml document when setting the xml property. The textual representations are returned schema and xml properties.

Successfully setting the xml property generates the object representation of the xml as well. This is taken care of by the subclass implementations of the __xml_to_obj method.

def __init__(self, typedefschema):

A class instance is initalized with a type definition schema:

>>> from simo.builder.xmlobject import XmlObject
>>> s = '''<xs:schema xmlns:xs="http://www.w3.org/2001/XMLSchema">
...         <xs:simpleType name="ListOfIntDouble">
...            <xs:list>
...               <xs:simpleType>
...                  <xs:union memberTypes="xs:int xs:double"/>
...               </xs:simpleType>
...            </xs:list>
...         </xs:simpleType>
...        </xs:schema>'''
>>> xo = XmlObject(s)
>>> xo.typedef_schema[:10]
'<xs:schema'
>>> xo.all_ok
False

def __set_schema(self, schematext):

Invalid schema leads to None value for schema property:

>>> s = '''<xs:schema xmlns:xs="http://www.w3.org/2001/XMLSchema">
...           <xs:element name="test">
...              <xs:element name="notvalid"/>
...           </xs:element>
...        </xs:schema>'''
>>> xo.schema = s 
Traceback (most recent call last):
  ...
XMLSchemaParseError: Element '{http://www.w3.org/2001/XMLSchema}element': The content is not valid. Expected is (annotation?, ((simpleType | complexType)?, (unique | key | keyref)*))., line 3
>>> xo.schema

Valid schema document is stored as text into the schema property:

>>> s = '''<xs:schema xmlns:xs="http://www.w3.org/2001/XMLSchema">
...           <xs:element name="test"/>
...        </xs:schema>'''
>>> xo.schema = s
>>> xo.schema[:10]
'<xs:schema'
>>> xo.all_ok
False

A schema containing an include will inherit the contents of the typedef_schema, the schema text will retain the include element, but the parser will have the types defined in the typedef document:

>>> s = '''<xs:schema xmlns:xs="http://www.w3.org/2001/XMLSchema">
...           <xs:include schemaLocation="../dir/dir.2/Typedefs_SIMO.xsd"/>
...           <xs:element name="test" type="ListOfIntDouble"/>
...        </xs:schema>'''
>>> xo.schema = s
>>> 'xs:include' in xo.schema
True

The include must be for the document Typedefs_SIMO.xsd, other references will generate an error:

>>> snot = '''<xs:schema xmlns:xs="http://www.w3.org/2001/XMLSchema">
...           <xs:include schemaLocation="some_other_def.xsd"/>
...           <xs:element name="test" type="ListOfIntDouble"/>
...        </xs:schema>'''
>>> xo.schema = snot 
Traceback (most recent call last):
     ...
XMLSchemaParseError: ...ailed to load...some_other_def.xsd...
>>> xo.schema = s

def __set_xml(self, xmldata):

With valid schema and xml a dictionary entry is created with the given name as key and the xml text as data:

>>> xo.xml = ('testdata', '<test>1 2 3</test>', None)
>>> xo.xml
{'testdata': '<test>1 2 3</test>'}
>>> xo.ok['testdata']
True
>>> xo.all_ok
True

With invalid xml, no entry is created in the xml dictionary:

>>> xo.xml = ('notvalid', '<nottest>test</nottest>', None)
Traceback (most recent call last):
  ...
ValueError: Element 'nottest': No matching global declaration available for the validation root.
>>> xo.xml = ('notvalideither', '<test>a b c</test>', None)
Traceback (most recent call last):
  ...
ValueError: Element 'test': 'a' is not a valid value of the local union type.
>>> xo.xml
{'testdata': '<test>1 2 3</test>'}
>>> xo.ok['testdata']
True
>>> xo.all_ok
True

Changing the schema invalidates the state of the typedef-schema-xml combination, unless the set schema is identical to the current one. However, the xml content is kept intact:

>>> s = xo.schema
>>> xo.schema = s
>>> xo.xml
{'testdata': '<test>1 2 3</test>'}
>>> xo.ok['testdata']
True
>>> s1 = '<xs:schema xmlns:xs="http://www.w3.org/2001/XMLSchema"><xs:element name="testtoo"/></xs:schema>'
>>> xo.schema = s1
>>> xo.xml
{'testdata': '<test>1 2 3</test>'}
>>> xo.ok['testdata']
False
>>> xo.all_ok
False

def xml_to_obj(self, root, lexicon):

Converts the XML representation to an object instance. For those XML documents that are tied to the SIMO lexicon definition; i.e., containing variable and data level definitions, the lexicon object instance is used to validate the XML document content against the lexicon content.

If the XML to object conversion is unsuccessful, the ok property for the XML name will be set to False as well as the all_ok property. If it is successful, the ok property for the XML name will be set to True, and all the other entries in the ok property will be scanned for False values. If none are found, the all_ok property will be set to True as well.

Each subclass of XmlObject will provide an implementation for this method.

def reparse(self, lexicon=None):

Used to explicitly parse the schema and xml content again after typedef or schema changes:

>>> s = '''<xs:schema xmlns:xs="http://www.w3.org/2001/XMLSchema">
...           <xs:element name="test" type="xs:string"/>
...        </xs:schema>'''
>>> xo.schema = s
>>> tds = '''<xs:schema xmlns:xs="http://www.w3.org/2001/XMLSchema">
...         <xs:simpleType name="doopidoo">
...            <xs:list itemType="xs:string"/>
...         </xs:simpleType>
...        </xs:schema>'''
>>> xo.typedef_schema = tds
>>> xo.all_ok
False
>>> xo.ok['testdata']
False
>>> xo.reparse()
>>> xo.ok['testdata']
True
>>> xo.all_ok
True
>>> 'doopidoo' in xo.typedef_schema
True
>>> 'xs:string' in xo.schema
True

def level_ind(self, level):

Checks whether a lexicon is defined, and whether the level can be found in the lexicon. Logs an error message if either of these fail and returns None, else returns the level index number for data matrix:

>>> xo.lexicon

>>> xo.errors
set([])
>>> xo.from_module = 'testmodule'
>>> xo.level_ind('comp_unit')

>>> xo.errors
set(["No lexicon set when validating level for testmodule 'testdata'"])
>>> class Lexicon(object):
...     def get_level_ind(self, level):
...         if level == 'comp_unit': return 1
...         else: return None
...     def get_variable_ind(self, level, var, active=False):
...         if level == 'comp_unit' and var == 'TS':
...             return (1, 1)
...         else:
...             return (None, None)
>>> xo.lexicon = Lexicon()
>>> xo.clear_warnings_and_errors()
>>> xo.level_ind('comp_unit')
1
>>> xo.errors
set([])
>>> xo.level_ind('non existing')

>>> xo.errors
set(["Level 'non existing' not found in lexicon for testmodule 'testdata'"])

def variable_ind(self, level, var):

Checks whether a lexicon is defined, and whether the variable at the given level can be found in the lexicon. Logs an error message if either of these fail and returns (None, None), else returns a tuple of level index and variable index for the data matrix:

>>> xo.variable_ind('comp_unit', 'TS')
(1, 1)
>>> xo.variable_ind('comp_unit', 'X')
(None, None)
>>> xo.errors
set(["Variable 'X' not found at level 'comp_unit' in lexicon for testmodule 'testdata'", "Level 'non existing' not found in lexicon for testmodule 'testdata'"])

def elem_namespace(elemtag):

Returns the namespace of an XML element:

>>> from lxml import etree
>>> root = etree.fromstring('<root xmlns="http://www.simo-project.org/simo"><tag/></root>')
>>> xo.elem_namespace(root.tag)
'{http://www.simo-project.org/simo}'

def elem_name(elemtag):

Returns the tag name of an XML element:

>>> xo.elem_name(root.tag)
'root'

def add_warning(self, msg):

Appends the message into the list contained in the warnings attribute.

def add_error(self, msg):

Adds the error message into the set contained in the errors attribute.

def clear_warnings_and_errors(self):

>>> xo.clear_warnings_and_errors()
>>> xo.warnings
[]
>>> xo.errors
set([])