Parse a content type rule.  Unlike the other rules, content type
    rules are more complex, since both selected content type and API
    version must be expressed by one rule.  The rule is split on
    whitespace, then the components beginning with "type:" and
    "version:" are selected; in both cases, the text following the ":"
    character will be treated as a format string, which will be
    formatted using a content parameter dictionary.  Components
    beginning with "param:" specify key="quoted value" pairs that
    specify parameters; these parameters are ignored by AVersion, but
    may be used by the application.

    :param ctype: The content type the rule is for.
    :param typespec: The rule text, described above.

    :returns: An instance of TypeRule.

def _parse_type_rule(ctype, typespec):
    """
    Parse a content type rule.  Unlike the other rules, content type
    rules are more complex, since both selected content type and API
    version must be expressed by one rule.  The rule is split on
    whitespace, then the components beginning with "type:" and
    "version:" are selected; in both cases, the text following the ":"
    character will be treated as a format string, which will be
    formatted using a content parameter dictionary.  Components
    beginning with "param:" specify key="quoted value" pairs that
    specify parameters; these parameters are ignored by AVersion, but
    may be used by the application.

    :param ctype: The content type the rule is for.
    :param typespec: The rule text, described above.

    :returns: An instance of TypeRule.
    """

    params = {'param': {}}
    for token in quoted_split(typespec, ' ', quotes='"\''):
        if not token:
            continue

        tok_type, _sep, tok_val = token.partition(':')

        # Validate the token type
        if not tok_val:
            LOG.warn("%s: Invalid type token %r" % (ctype, token))
            continue
        elif tok_type not in ('type', 'version', 'param'):
            LOG.warn("%s: Unrecognized token type %r" % (ctype, tok_type))
            continue

        # Intercept 'param' clauses
        if tok_type == 'param':
            key, _eq, value = tok_val.partition('=')

            # Set the parameter key
            _set_key('type.%s' % ctype, params['param'], key, value)
            continue

        # Set the token value
        _set_key('type.%s' % ctype, params, tok_type, tok_val,
                 desc="token type")

    return TypeRule(ctype=params.get('type'),
                    version=params.get('version'),
                    params=params['param'])