convert_tag

        High-level api: Convert a tag or an identifier from one notation to
        another. Notations are defined by tuple constants in yang.ncdiff.Tag.

        Parameters
        ----------

        default_ns : `str`
            The default namespace. Usually it's the namespace of parent node. It
            could be a model name, a model prefix, or a model URL, depending on
            your argument 'src'. An empty string is considered as none default
            namespace.

        tag : `str`
            A tag or an identifier of a config node or a schema node.

        src : `tuple`
            The type of notation the input tag is, which is a tuple constant
            defined in yang.ncdiff.Tag. Most commonly it could be Tag.XPATH or
            Tag.LXML_XPATH.

        dst : `tuple`
            The type of notation we want, which is a tuple constant defined in
            yang.ncdiff.Tag. Most commonly it could be Tag.XPATH or
            Tag.LXML_XPATH.

        Returns
        -------

        tuple
            A tuple that has two elements: The first element is the namespace of
            argument 'tag'. It could be a model name, a model prefix, or a model
            URL, depending on your argument 'src'. The second element is the
            converted tag or identifier, which is in notation specified by
            argument 'dst'.


        Code Example::

            >>> device.nc.convert_tag('',
                                      '{http://openconfig.net/yang/interfaces}interface',
                                      dst=Tag.JSON_NAME)
            ('http://openconfig.net/yang/interfaces', 'openconfig-interfaces:interface')
            >>>

def convert_tag(self, default_ns, tag, src=Tag.LXML_ETREE, dst=Tag.YTOOL):
        '''convert_tag

        High-level api: Convert a tag or an identifier from one notation to
        another. Notations are defined by tuple constants in yang.ncdiff.Tag.

        Parameters
        ----------

        default_ns : `str`
            The default namespace. Usually it's the namespace of parent node. It
            could be a model name, a model prefix, or a model URL, depending on
            your argument 'src'. An empty string is considered as none default
            namespace.

        tag : `str`
            A tag or an identifier of a config node or a schema node.

        src : `tuple`
            The type of notation the input tag is, which is a tuple constant
            defined in yang.ncdiff.Tag. Most commonly it could be Tag.XPATH or
            Tag.LXML_XPATH.

        dst : `tuple`
            The type of notation we want, which is a tuple constant defined in
            yang.ncdiff.Tag. Most commonly it could be Tag.XPATH or
            Tag.LXML_XPATH.

        Returns
        -------

        tuple
            A tuple that has two elements: The first element is the namespace of
            argument 'tag'. It could be a model name, a model prefix, or a model
            URL, depending on your argument 'src'. The second element is the
            converted tag or identifier, which is in notation specified by
            argument 'dst'.


        Code Example::

            >>> device.nc.convert_tag('',
                                      '{http://openconfig.net/yang/interfaces}interface',
                                      dst=Tag.JSON_NAME)
            ('http://openconfig.net/yang/interfaces', 'openconfig-interfaces:interface')
            >>>
        '''

        def possible_part1():
            if src[0] == Tag.NAME:
                return [i[0] for i in self.namespaces]
            elif src[0] == Tag.PREFIX:
                return [i[1] for i in self.namespaces] + \
                       list(special_prefixes.values())
            else:
                return [i[2] for i in self.namespaces] + \
                       list(special_prefixes.keys())

        def split_tag(tag):
            ret = re.search(src[2][0], tag)
            if ret:
                if ret.group(1) in possible_part1():
                    return (ret.group(1), ret.group(2))
                else:
                    return ('', tag)
            else:
                return ('', tag)

        def format_tag(tag_ns, tag_name):
            if tag_ns:
                return dst[2][1].format(tag_ns, tag_name)
            else:
                return tag_name

        def convert(ns):
            matches = [i for i in self.namespaces if i[src[0]] == ns]
            c = len(matches)
            if c > 1:
                raise ModelError("device supports more than one {} '{}': {}" \
                                 .format(Tag.STR[src[0]], ns, matches))
            if c == 1:
                return matches[0][dst[0]]
            if src[0] != Tag.NAME and dst[0] != Tag.NAME:
                special = [('', v, k) for k, v in special_prefixes.items()]
                matches = [i for i in special if i[src[0]] == ns]
                if len(matches) == 1:
                    return matches[0][dst[0]]
            raise ValueError("device does not support {} '{}' " \
                             "when parsing tag '{}'" \
                             .format(Tag.STR[src[0]], ns, tag))

        tag_ns, tag_name = split_tag(tag)
        if src[1] == Tag.NO_OMIT and not tag_ns:
            raise ValueError("tag '{}' does not contain prefix or namespace " \
                             "but it is supposed to be Tag.NO_OMIT" \
                             .format(tag))
        elif not tag_ns:
            tag_ns = default_ns
        if dst[1] == Tag.NO_OMIT:
            return tag_ns, format_tag(convert(tag_ns), tag_name)
        elif dst[1] == Tag.OMIT_BY_INHERITANCE:
            if default_ns == tag_ns:
                return default_ns, format_tag('', tag_name)
            else:
                return tag_ns, format_tag(convert(tag_ns), tag_name)
        elif dst[1] == Tag.OMIT_BY_MODULE:
            if default_ns == tag_ns:
                return default_ns, format_tag('', tag_name)
            else:
                return default_ns, format_tag(convert(tag_ns), tag_name)
        else:
            raise ValueError("unknown value '{}' in class Tag".format(dst[1]))