def xml_to_json(element, definition, required=False):
    # TODO document tuple - it looks little too complex
    """Convert XML (ElementTree) to dictionary from a definition schema.

    Definition schema can be a simple string - XPath or @attribute for
    direct extraction or a complex one described by

    * dictionary ``{key: 'xpath or @attribute', second: 'complex definition'}`` \
      required parameters can be marked with * at the end
    * list ``[xpath, [definition]]`` - create a list of all elements found by \
      xpath, parse the parts with given definition if provided as second \
      argument
    * Callable - parse the element by given function, can be handy as a part \
      of complex definition

    :param element: ElementTree element
    :type element: ElementTree.Element
    :param definition: schema for the json
    :type definition: Union[str, tuple, dict, list, Callable]
    :param required: parsed value should be not None
    :type required: bool
    :return: parsed xml
    :rtype: Union[dict, str, list]
    """
    # handle simple definition
    if isinstance(definition, str) and len(definition) > 0:
        if definition[0] == '@':  # test for attribute
            return element.get(definition[1:])

        # get tag text
        else:
            sub_element = element.find(definition)

            if sub_element is None:
                if required:
                    raise NotCompleteXmlException('Expecting {0} in element {1}'.format(definition, element.tag))
                return None

            return sub_element.text.strip() if sub_element.text else None

            # handle tuple
    elif isinstance(definition, tuple):
        return _parse_tuple(element, definition, required)

    # handle dict
    elif isinstance(definition, dict):
        return _parse_dict(element, definition)

    # handle list
    elif isinstance(definition, list):
        return _parse_list(element, definition)

    elif hasattr(definition, '__call__'):
        return definition(element)

    # default
    else:
        return element.text.strip() if element.text else None