'Return sympy expression for the math formula.
The math formula is converted to Content MathML then that is parsed.
This is a recursive function, called on every CMML node. Support for
more functions can be added by modifying opdict, abould halfway down'

def make_sympy(self, xml=None):

    if self.the_sympy:
        return self.the_sympy
    if (xml is None):
        if (not self.is_mathml()):
            return my_sympify(self.expr)
        if self.is_presentation_mathml():
            cmml = None
            try:
                cmml = self.cmathml
                xml = etree.fromstring(str(cmml))
            except Exception as err:
                if ('conversion    from    Presentation    MathML    to    Content    MathML    was    not    successful' in cmml):
                    msg = 'Illegal    math    expression'
                else:
                    msg = ('Err    %s    while    converting    cmathml    to    xml;    cmml=%s' % (err, cmml))
                raise Exception(msg)
            xml = self.fix_greek_in_mathml(xml)
            self.the_sympy = self.make_sympy(xml[0])
        else:
            xml = etree.fromstring(self.expr)
            xml = self.fix_greek_in_mathml(xml)
            self.the_sympy = self.make_sympy(xml[0])
        return self.the_sympy
    def gettag(expr):
        return re.sub('{http://[^}]+}', '', expr.tag)
    def op_plus(*args):
        return (args[0] if (len(args) == 1) else (op_plus(*args[:(-1)]) + args[(-1)]))
    def op_times(*args):
        return reduce(operator.mul, args)
    def op_minus(*args):
        if (len(args) == 1):
            return (- args[0])
        if (not (len(args) == 2)):
            raise Exception('minus    given    wrong    number    of    arguments!')
        return (args[0] - args[1])
    opdict = {'plus': op_plus, 'divide': operator.div, 'times': op_times, 'minus': op_minus, 'root': sympy.sqrt, 'power': sympy.Pow, 'sin': sympy.sin, 'cos': sympy.cos, 'tan': sympy.tan, 'cot': sympy.cot, 'sinh': sympy.sinh, 'cosh': sympy.cosh, 'coth': sympy.coth, 'tanh': sympy.tanh, 'asin': sympy.asin, 'acos': sympy.acos, 'atan': sympy.atan, 'atan2': sympy.atan2, 'acot': sympy.acot, 'asinh': sympy.asinh, 'acosh': sympy.acosh, 'atanh': sympy.atanh, 'acoth': sympy.acoth, 'exp': sympy.exp, 'log': sympy.log, 'ln': sympy.ln}
    def parse_presentation_symbol(xml):
        '\n                                                Parse    <msub>,    <msup>,    <mi>,    and    <mn>\n                                                '
        tag = gettag(xml)
        if (tag == 'mn'):
            return xml.text
        elif (tag == 'mi'):
            return xml.text
        elif (tag == 'msub'):
            return '_'.join([parse_presentation_symbol(y) for y in xml])
        elif (tag == 'msup'):
            return '^'.join([parse_presentation_symbol(y) for y in xml])
        raise Exception(('[parse_presentation_symbol]    unknown    tag    %s' % tag))
    tag = gettag(xml)
    if (tag == 'apply'):
        opstr = gettag(xml[0])
        if (opstr in opdict):
            op = opdict[opstr]
            args = [self.make_sympy(expr) for expr in xml[1:]]
            try:
                res = op(*args)
            except Exception as err:
                self.args = args
                self.op = op
                raise Exception(('[formula]    error=%s    failed    to    apply    %s    to    args=%s' % (err, opstr, args)))
            return res
        else:
            raise Exception(('[formula]:    unknown    operator    tag    %s' % opstr))
    elif (tag == 'list'):
        if (gettag(xml[0]) == 'matrix'):
            return self.make_sympy(xml[0])
        else:
            return [self.make_sympy(expr) for expr in xml]
    elif (tag == 'matrix'):
        return sympy.Matrix([self.make_sympy(expr) for expr in xml])
    elif (tag == 'vector'):
        return [self.make_sympy(expr) for expr in xml]
    elif (tag == 'cn'):
        return sympy.sympify(xml.text)
    elif (tag == 'ci'):
        if ((len(xml) > 0) and ((gettag(xml[0]) == 'msub') or (gettag(xml[0]) == 'msup'))):
            usym = parse_presentation_symbol(xml[0])
            sym = sympy.Symbol(str(usym))
        else:
            usym = unicode(xml.text)
            if ('hat' in usym):
                sym = my_sympify(usym)
            elif ((usym == 'i') and (self.options is not None) and ('imaginary' in self.options)):
                sym = sympy.I
            else:
                sym = sympy.Symbol(str(usym))
        return sym
    else:
        raise Exception(('[formula]    unknown    tag    %s' % tag))
