def _primative_to_document(data, base_url=None):
    """
    Take Python primatives as returned from parsing JSON content,
    and return a Core API document.
    """
    if isinstance(data, dict) and data.get('_type') == 'document':
        # Document
        meta = _get_dict(data, '_meta')
        url = _get_string(meta, 'url')
        url = urlparse.urljoin(base_url, url)
        title = _get_string(meta, 'title')
        content = _get_content(data, base_url=url)
        return Document(url=url, title=title, content=content)

    if isinstance(data, dict) and data.get('_type') == 'error':
        # Error
        meta = _get_dict(data, '_meta')
        title = _get_string(meta, 'title')
        content = _get_content(data, base_url=base_url)
        return Error(title=title, content=content)

    elif isinstance(data, dict) and data.get('_type') == 'link':
        # Link
        url = _get_string(data, 'url')
        url = urlparse.urljoin(base_url, url)
        action = _get_string(data, 'action')
        encoding = _get_string(data, 'encoding')
        transform = _get_string(data, 'transform')
        description = _get_string(data, 'description')
        fields = _get_list(data, 'fields')
        fields = [
            Field(name=_get_string(item, 'name'),
                  required=_get_bool(item, 'required'),
                  location=_get_string(item, 'location'),
                  type=_get_string(item, 'type'),
                  description=_get_string(item, 'description'))
            for item in fields if isinstance(item, dict)
        ]
        return Link(url=url,
                    action=action,
                    encoding=encoding,
                    transform=transform,
                    description=description,
                    fields=fields)

    elif isinstance(data, dict):
        # Map
        content = _get_content(data, base_url=base_url)
        return Object(content)

    elif isinstance(data, list):
        # Array
        content = [_primative_to_document(item, base_url) for item in data]
        return Array(content)

    # String, Integer, Number, Boolean, null.
    return data
def _primative_to_document(data, base_url=None):
    """
    Take Python primatives as returned from parsing JSON content,
    and return a Core API document.
    """
    if isinstance(data, dict) and data.get('_type') == 'document':
        # Document
        meta = _get_dict(data, '_meta')
        url = _get_string(meta, 'url')
        url = urlparse.urljoin(base_url, url)
        title = _get_string(meta, 'title')
        content = _get_content(data, base_url=url)
        return Document(url=url, title=title, content=content)

    if isinstance(data, dict) and data.get('_type') == 'error':
        # Error
        meta = _get_dict(data, '_meta')
        title = _get_string(meta, 'title')
        content = _get_content(data, base_url=base_url)
        return Error(title=title, content=content)

    elif isinstance(data, dict) and data.get('_type') == 'link':
        # Link
        url = _get_string(data, 'url')
        url = urlparse.urljoin(base_url, url)
        action = _get_string(data, 'action')
        encoding = _get_string(data, 'encoding')
        transform = _get_string(data, 'transform')
        description = _get_string(data, 'description')
        fields = _get_list(data, 'fields')
        fields = [
            Field(
                name=_get_string(item, 'name'),
                required=_get_bool(item, 'required'),
                location=_get_string(item, 'location'),
                description=_get_string(item, 'description')
            )
            for item in fields if isinstance(item, dict)
        ]
        return Link(
            url=url, action=action, encoding=encoding, transform=transform,
            description=description, fields=fields
        )

    elif isinstance(data, dict):
        # Map
        content = _get_content(data, base_url=base_url)
        return Object(content)

    elif isinstance(data, list):
        # Array
        content = [_primative_to_document(item, base_url) for item in data]
        return Array(content)

    # String, Integer, Number, Boolean, null.
    return data
Esempio n. 3
0
def _render_html(node, url=None, key=None, path=''):
    if key:
        path += "%s." % key

    if isinstance(node, (Document, Link)):
        url = urlparse.urljoin(url, node.url)

    if isinstance(node, Document):
        template = env.get_template('document.html')
    elif isinstance(node, Object):
        template = env.get_template('object.html')
    elif isinstance(node, Array):
        template = env.get_template('array.html')
    elif isinstance(node, Link):
        template = env.get_template('link.html')
    elif isinstance(node, Error):
        template = env.get_template('error.html')
    elif node is None or isinstance(node, bool):
        value = {True: 'true', False: 'false', None: 'null'}[node]
        return "<code>%s</code>" % value
    elif isinstance(node, (float, int)):
        return "<code>%s</code>" % node
    else:
        return "<span>%s</span>" % node.replace('\n', '<br/>')

    return template.render(node=node, render=_render_html, url=url, key=key, path=path)
Esempio n. 4
0
def _parse_link(data, base_url=None):
    url = _get_string(data, 'href')
    url = urlparse.urljoin(base_url, url)
    if _get_bool(data, 'templated'):
        fields = [
            Field(name, location='path') for name in uritemplate.variables(url)
        ]
    else:
        fields = None
    return Link(url=url, fields=fields)
Esempio n. 5
0
def _parse_link(data, base_url=None):
    url = _get_string(data, 'href')
    url = urlparse.urljoin(base_url, url)
    if _get_bool(data, 'templated'):
        fields = [
            Field(name, location='path') for name in uritemplate.variables(url)
        ]
    else:
        fields = None
    return Link(url=url, fields=fields)
Esempio n. 6
0
def _parse_document(data, base_url=None):
    schema_url = base_url
    base_url = _get_document_base_url(data, base_url)
    info = _get_dict(data, 'info')
    title = _get_string(info, 'title')
    paths = _get_dict(data, 'paths')
    content = {}
    for path in paths.keys():
        url = urlparse.urljoin(base_url, path.lstrip('/'))
        spec = _get_dict(paths, path)
        default_parameters = get_dicts(_get_list(spec, 'parameters'))
        for action in spec.keys():
            action = action.lower()
            if action not in ('get', 'put', 'post', 'delete', 'options', 'head', 'patch'):
                continue
            operation = _get_dict(spec, action)

            # Determine any fields on the link.
            fields = []
            parameters = get_dicts(_get_list(operation, 'parameters', default_parameters), dereference_using=data)
            for parameter in parameters:
                name = _get_string(parameter, 'name')
                location = _get_string(parameter, 'in')
                required = _get_bool(parameter, 'required', default=(location == 'path'))
                if location == 'body':
                    schema = _get_dict(parameter, 'schema', dereference_using=data)
                    expanded = _expand_schema(schema)
                    if expanded is not None:
                        expanded_fields = [
                            Field(name=field_name, location='form', required=is_required)
                            for field_name, is_required in expanded
                            if not any([field.name == name for field in fields])
                        ]
                        fields += expanded_fields
                    else:
                        field = Field(name=name, location='body', required=True)
                        fields.append(field)
                else:
                    field = Field(name=name, location=location, required=required)
                    fields.append(field)
            link = Link(url=url, action=action, fields=fields)

            # Add the link to the document content.
            tags = get_strings(_get_list(operation, 'tags'))
            operation_id = _get_string(operation, 'operationId')
            if tags:
                for tag in tags:
                    if tag not in content:
                        content[tag] = {}
                    content[tag][operation_id] = link
            else:
                content[operation_id] = link

    return Document(url=schema_url, title=title, content=content)
Esempio n. 7
0
def _get_content(data, base_url, ref):
    content = {}
    links = _get_list(data, 'links')
    properties = _get_dict(data, 'properties')

    if properties:
        for key, value in properties.items():
            if not isinstance(value, dict):
                continue
            if list(value.keys()) == ['$ref']:
                value = _dereference(value['$ref'], ref)
            sub_content = _get_content(value, base_url, ref)
            if sub_content:
                content[key] = sub_content
    if links:
        for link in get_dicts(links):
            rel = _get_string(link, 'rel')
            if rel:
                href = _get_string(link, 'href')
                method = _get_string(link, 'method')
                schema = _get_dict(link, 'schema')
                schema_type = _get_list(schema, 'type')
                schema_properties = _get_dict(schema, 'properties')
                schema_required = _get_list(schema, 'required')

                fields = []
                url = urlparse.urljoin(base_url, href)
                templated = uritemplate.variables(url)
                for item in templated:
                    orig = item
                    if item.startswith('(') and item.endswith(')'):
                        item = unquote(item.strip('(').rstrip(')'))
                    if item.startswith('#/'):
                        components = [
                            component
                            for component in item.strip('#/').split('/')
                            if component != 'definitions'
                        ]
                    item = '_'.join(components).replace('-', '_')
                    url = url.replace(orig, item)
                    fields.append(
                        Field(name=item, location='path', required=True))

                if schema_type == ['object'] and schema_properties:
                    fields += [
                        Field(name=key, required=(key in schema_required))
                        for key in schema_properties.keys()
                    ]
                if rel == 'self':
                    rel = 'read'
                content[rel] = Link(url=url, action=method, fields=fields)

    return content
    def _yaml_include(self, loader, node):
        url = urlparse.urljoin(self.base_url, node.value)
        path = urlparse.urlparse(url).path
        ext = posixpath.splitext(path)[1]

        response = requests.get(url)
        if ext in [".yaml", ".yml", ".raml"]:
            return yaml.load(response.content, self._ordered_loader)
        elif ext == '.json':
            return jsonref.loads(response.text,
                                 base_uri=self.base_url,
                                 jsonschema=True)
        return response.text
Esempio n. 9
0
def _get_content(data, base_url, ref):
    content = {}
    links = _get_list(data, 'links')
    properties = _get_dict(data, 'properties')

    if properties:
        for key, value in properties.items():
            if not isinstance(value, dict):
                continue
            if list(value.keys()) == ['$ref']:
                value = _dereference(value['$ref'], ref)
            sub_content = _get_content(value, base_url, ref)
            if sub_content:
                content[key] = sub_content
    if links:
        for link in get_dicts(links):
            rel = _get_string(link, 'rel')
            if rel:
                href = _get_string(link, 'href')
                method = _get_string(link, 'method')
                schema = _get_dict(link, 'schema')
                schema_type = _get_list(schema, 'type')
                schema_properties = _get_dict(schema, 'properties')
                schema_required = _get_list(schema, 'required')

                fields = []
                url = urlparse.urljoin(base_url, href)
                templated = uritemplate.variables(url)
                for item in templated:
                    orig = item
                    if item.startswith('(') and item.endswith(')'):
                        item = urllib.unquote(item.strip('(').rstrip(')'))
                    if item.startswith('#/'):
                        components = [
                            component for component in item.strip('#/').split('/')
                            if component != 'definitions'
                        ]
                    item = '_'.join(components).replace('-', '_')
                    url = url.replace(orig, item)
                    fields.append(Field(name=item, location='path', required=True))

                if schema_type == ['object'] and schema_properties:
                    fields += [
                        Field(name=key, required=key in schema_required)
                        for key in schema_properties.keys()
                    ]
                if rel == 'self':
                    rel = 'read'
                content[rel] = Link(url=url, action=method, fields=fields)

    return content
Esempio n. 10
0
def _parse_document(data, base_url=None):
    links = _get_dict(data, '_links')
    embedded = _get_dict(data, '_embedded')

    self = _get_dict(links, 'self')
    url = _get_string(self, 'href')
    url = urlparse.urljoin(base_url, url)
    title = _get_string(self, 'title')

    content = {}

    for key, value in links.items():
        if key in ('self', 'curies'):
            continue

        key = _map_to_coreapi_key(key)

        if isinstance(value, list):
            if value and 'name' in value[0]:
                # Lists of named links should be represented inside a map.
                content[key] = {
                    item['name']: _parse_link(item, base_url)
                    for item in value
                    if 'name' in item
                }
            else:
                # Lists of named links should be represented inside a list.
                content[key] = [
                    _parse_link(item, base_url)
                    for item in value
                ]
        elif isinstance(value, dict):
            # Single link instance.
            content[key] = _parse_link(value, base_url)

    # Embedded resources.
    for key, value in embedded.items():
        key = _map_to_coreapi_key(key)
        if isinstance(value, list):
            content[key] = [_parse_document(item, base_url=url) for item in value]
        elif isinstance(value, dict):
            content[key] = _parse_document(value, base_url=url)

    # Data.
    for key, value in data.items():
        if key not in ('_embedded', '_links'):
            content[key] = value

    return Document(url=url, title=title, content=content)
Esempio n. 11
0
def _primative_to_document(data, base_url):
    url = base_url

    # Determine if the document contains a self URL.
    links = _get_list(data, 'links')
    for link in get_dicts(links):
        href = _get_string(link, 'href')
        rel = _get_string(link, 'rel')
        if rel == 'self' and href:
            url = urlparse.urljoin(url, href)

    # Load the document content.
    title = _get_string(data, 'title')
    content = _get_content(data, url, ref=data)
    return Document(title=title, url=url, content=content)
Esempio n. 12
0
def _primative_to_document(data, base_url):
    url = base_url

    # Determine if the document contains a self URL.
    links = _get_list(data, 'links')
    for link in get_dicts(links):
        href = _get_string(link, 'href')
        rel = _get_string(link, 'rel')
        if rel == 'self' and href:
            url = urlparse.urljoin(url, href)

    # Load the document content.
    title = _get_string(data, 'title')
    content = _get_content(data, url, ref=data)
    return Document(title=title, url=url, content=content)
Esempio n. 13
0
def _parse_document(data, base_url=None):
    links = _get_dict(data, '_links')
    embedded = _get_dict(data, '_embedded')

    self = _get_dict(links, 'self')
    url = _get_string(self, 'href')
    url = urlparse.urljoin(base_url, url)
    title = _get_string(self, 'title')

    content = {}

    for key, value in links.items():
        if key in ('self', 'curies'):
            continue

        key = _map_to_coreapi_key(key)

        if isinstance(value, list):
            if value and 'name' in value[0]:
                # Lists of named links should be represented inside a map.
                content[key] = {
                    item['name']: _parse_link(item, base_url)
                    for item in value if 'name' in item
                }
            else:
                # Lists of named links should be represented inside a list.
                content[key] = [_parse_link(item, base_url) for item in value]
        elif isinstance(value, dict):
            # Single link instance.
            content[key] = _parse_link(value, base_url)

    # Embedded resources.
    for key, value in embedded.items():
        key = _map_to_coreapi_key(key)
        if isinstance(value, list):
            content[key] = [
                _parse_document(item, base_url=url) for item in value
            ]
        elif isinstance(value, dict):
            content[key] = _parse_document(value, base_url=url)

    # Data.
    for key, value in data.items():
        if key not in ('_embedded', '_links'):
            content[key] = value

    return Document(url=url, title=title, content=content)
Esempio n. 14
0
def _render_html(node, url=None, key=None):
    if isinstance(node, (Document, Link)):
        url = urlparse.urljoin(url, node.url)

    if isinstance(node, Document):
        template = env.get_template('document.html')
    elif isinstance(node, Object):
        template = env.get_template('object.html')
    elif isinstance(node, Array):
        template = env.get_template('array.html')
    elif isinstance(node, Link):
        template = env.get_template('link.html')
    elif isinstance(node, Error):
        template = env.get_template('error.html')
    elif node in (True, False, None):
        value = {True: 'true', False: 'false', None: 'null'}[node]
        return "<code>%s</code>" % value
    elif isinstance(node, (float, int)):
        return "<code>%s</code>" % node
    else:
        return "<span>%s</span>" % node

    return template.render(node=node, render=_render_html, url=url, key=key)
Esempio n. 15
0
def _document_to_primative(node, base_url=None):
    if isinstance(node, Document):
        url = urlparse.urljoin(base_url, node.url)
        links = OrderedDict()
        embedded = OrderedDict()
        data = OrderedDict()

        self_link = OrderedDict()
        self_link['href'] = url
        if node.title:
            self_link['title'] = node.title
        links['self'] = self_link

        for key, value in node.items():
            if isinstance(value, Link):
                links[key] = _document_to_primative(value, base_url=url)
            elif _is_array_containing_instance(value, Link):
                links[key] = [
                    _document_to_primative(item, base_url=url)
                    for item in value if isinstance(item, Link)
                ]
            elif _is_map_containing_instance(value, Link):
                links[key] = {
                    key: _document_to_primative(val, base_url=url)
                    for key, val in value.items() if isinstance(val, Link)
                }
            elif isinstance(value, Document):
                embedded[key] = _document_to_primative(value, base_url=url)
            elif _is_array_containing_instance(value, Document):
                embedded[key] = [
                    _document_to_primative(item, base_url=url)
                    for item in value if isinstance(item, Document)
                ]
            elif key not in ('_links', '_embedded'):
                data[key] = _document_to_primative(value)

        ret = OrderedDict()
        ret['_links'] = links
        ret.update(data)
        if embedded:
            ret['_embedded'] = embedded
        return ret

    elif isinstance(node, Link):
        url = urlparse.urljoin(base_url, node.url)
        ret = OrderedDict()
        ret['href'] = url
        templated = [
            field.name for field in node.fields if field.location == 'path'
        ]
        if templated:
            ret['href'] += "{?%s}" % ','.join([name for name in templated])
            ret['templated'] = True
        return ret

    elif isinstance(node, Array):
        return [_document_to_primative(item) for item in node]

    elif isinstance(node, Object):
        return OrderedDict([(key, _document_to_primative(value))
                            for key, value in node.items()
                            if not isinstance(value, (Document, Link))])

    elif isinstance(node, Error):
        return OrderedDict([(key, _document_to_primative(value))
                            for key, value in node.items()])

    return node
Esempio n. 16
0
def _primative_to_document(data, base_url=None):
    """
    Take Python primatives as returned from parsing JSON content,
    and return a Core API document.
    """
    if isinstance(data, dict) and data.get('_type') == 'document':
        meta = data.get('_meta', {})
        if not isinstance(meta, dict):
            meta = {}

        url = meta.get('url', '')
        if not isinstance(url, string_types):
            url = ''
        url = urlparse.urljoin(base_url, url)

        title = meta.get('title', '')
        if not isinstance(title, string_types):
            title = ''

        return Document(url=url, title=title, content={
            _unescape_key(key): _primative_to_document(value, url)
            for key, value in data.items()
            if key not in ('_type', '_meta')
        })

    elif isinstance(data, dict) and data.get('_type') == 'link':
        url = data.get('url', '')
        if not isinstance(url, string_types):
            url = ''
        url = urlparse.urljoin(base_url, url)

        trans = data.get('trans')
        if not isinstance(trans, string_types) or (trans not in _transition_types):
            trans = None

        fields = data.get('fields', [])
        if not isinstance(fields, list):
            fields = []
        else:
            # Ignore any field items that don't match the required structure.
            fields = [
                item for item in fields
                if isinstance(item, string_types) or (
                    isinstance(item, dict) and
                    isinstance(item.get('name'), string_types)
                )
            ]
            # Transform the strings or dicts into strings or Field instances.
            fields = [
                item if isinstance(item, string_types) else
                Field(item['name'], required=bool(item.get('required', False)))
                for item in fields
            ]

        return Link(url=url, trans=trans, fields=fields)

    elif isinstance(data, dict) and data.get('_type') == 'error':
        messages = data.get('messages', [])
        if not isinstance(messages, list):
            messages = []

        # Ignore any messages which are have incorrect type.
        messages = [
            message for message in messages
            if isinstance(message, string_types)
        ]

        return Error(messages)

    elif isinstance(data, dict):
        return Object({
            _unescape_key(key): _primative_to_document(value, base_url)
            for key, value in data.items()
            if key not in ('_type', '_meta')
        })

    elif isinstance(data, list):
        return Array([
            _primative_to_document(item, base_url) for item in data
        ])

    return data
Esempio n. 17
0
def _document_to_primative(node, base_url=None):
    if isinstance(node, Document):
        url = urlparse.urljoin(base_url, node.url)
        links = OrderedDict()
        embedded = OrderedDict()
        data = OrderedDict()

        self_link = OrderedDict()
        self_link['href'] = url
        if node.title:
            self_link['title'] = node.title
        links['self'] = self_link

        for key, value in node.items():
            if isinstance(value, Link):
                links[key] = _document_to_primative(value, base_url=url)
            elif _is_array_containing_instance(value, Link):
                links[key] = [
                    _document_to_primative(item, base_url=url)
                    for item in value
                    if isinstance(item, Link)
                ]
            elif _is_map_containing_instance(value, Link):
                links[key] = {
                    key: _document_to_primative(val, base_url=url)
                    for key, val in value.items()
                    if isinstance(val, Link)
                }
            elif isinstance(value, Document):
                embedded[key] = _document_to_primative(value, base_url=url)
            elif _is_array_containing_instance(value, Document):
                embedded[key] = [
                    _document_to_primative(item, base_url=url)
                    for item in value
                    if isinstance(item, Document)
                ]
            elif key not in ('_links', '_embedded'):
                data[key] = _document_to_primative(value)

        ret = OrderedDict()
        ret['_links'] = links
        ret.update(data)
        if embedded:
            ret['_embedded'] = embedded
        return ret

    elif isinstance(node, Link):
        url = urlparse.urljoin(base_url, node.url)
        ret = OrderedDict()
        ret['href'] = url
        templated = [field.name for field in node.fields if field.location == 'path']
        if templated:
            ret['href'] += "{?%s}" % ','.join([name for name in templated])
            ret['templated'] = True
        return ret

    elif isinstance(node, Array):
        return [
            _document_to_primative(item) for item in node
        ]

    elif isinstance(node, Object):
        return OrderedDict([
            (key, _document_to_primative(value)) for key, value in node.items()
            if not isinstance(value, (Document, Link))
        ])

    elif isinstance(node, Error):
        return OrderedDict([
            (key, _document_to_primative(value)) for key, value in node.items()
        ])

    return node
Esempio n. 18
0
def _primitive_to_document(data, base_url=None):
    """
    Take Python primitives as returned from parsing JSON content,
    and return a Core API document.
    """
    if isinstance(data, dict) and data.get("_type") == "document":
        # Document
        meta = _get_dict(data, "_meta")
        url = _get_string(meta, "url")
        url = urlparse.urljoin(base_url, url)
        title = _get_string(meta, "title")
        description = _get_string(meta, "description")
        content = _get_content(data, base_url=url)
        return Document(
            url=url,
            title=title,
            description=description,
            media_type="application/coreapi+json",
            content=content,
        )

    if isinstance(data, dict) and data.get("_type") == "error":
        # Error
        meta = _get_dict(data, "_meta")
        title = _get_string(meta, "title")
        content = _get_content(data, base_url=base_url)
        return Error(title=title, content=content)

    elif isinstance(data, dict) and data.get("_type") == "link":
        # Link
        url = _get_string(data, "url")
        url = urlparse.urljoin(base_url, url)
        action = _get_string(data, "action")
        encoding = _get_string(data, "encoding")
        transform = _get_string(data, "transform")
        title = _get_string(data, "title")
        description = _get_string(data, "description")
        fields = _get_list(data, "fields")
        fields = [
            Field(
                name=_get_string(item, "name"),
                required=_get_bool(item, "required"),
                location=_get_string(item, "location"),
                schema=_get_schema(item, "schema"),
            ) for item in fields if isinstance(item, dict)
        ]
        return Link(
            url=url,
            action=action,
            encoding=encoding,
            transform=transform,
            title=title,
            description=description,
            fields=fields,
        )

    elif isinstance(data, dict):
        # Map
        content = _get_content(data, base_url=base_url)
        return Object(content)

    elif isinstance(data, list):
        # Array
        content = [_primitive_to_document(item, base_url) for item in data]
        return Array(content)

    # String, Integer, Number, Boolean, null.
    return data
Esempio n. 19
0
def _parse_document(data, base_url=None):
    schema_url = base_url
    base_url = _get_document_base_url(data, base_url)
    info = _get_dict(data, 'info')
    title = _get_string(info, 'title')
    paths = _get_dict(data, 'paths')
    content = {}
    for path in paths.keys():
        url = urlparse.urljoin(base_url, path.lstrip('/'))
        spec = _get_dict(paths, path)
        default_parameters = get_dicts(_get_list(spec, 'parameters'))
        for action in spec.keys():
            action = action.lower()
            if action not in ('get', 'put', 'post', 'delete', 'options',
                              'head', 'patch'):
                continue
            operation = _get_dict(spec, action)

            # Determine any fields on the link.
            fields = []
            parameters = get_dicts(_get_list(operation, 'parameters',
                                             default_parameters),
                                   dereference_using=data)
            for parameter in parameters:
                name = _get_string(parameter, 'name')
                location = _get_string(parameter, 'in')
                required = _get_bool(parameter,
                                     'required',
                                     default=(location == 'path'))
                description = _get_string(parameter, 'description')
                if location == 'body':
                    schema = _get_dict(parameter,
                                       'schema',
                                       dereference_using=data)
                    expanded = _expand_schema(schema)
                    if expanded is not None:
                        expanded_fields = [
                            Field(name=field_name,
                                  location='form',
                                  required=is_required,
                                  description=description)
                            for field_name, is_required in expanded if
                            not any([field.name == name for field in fields])
                        ]
                        fields += expanded_fields
                    else:
                        field = Field(name=name,
                                      location='body',
                                      required=True,
                                      description=description)
                        fields.append(field)
                else:
                    field = Field(name=name,
                                  location=location,
                                  required=required,
                                  description=description)
                    fields.append(field)
            link = Link(url=url, action=action, fields=fields)

            # Add the link to the document content.
            tags = get_strings(_get_list(operation, 'tags'))
            operation_id = _get_string(operation, 'operationId')
            if tags:
                for tag in tags:
                    if tag not in content:
                        content[tag] = {}
                    content[tag][operation_id] = link
            else:
                content[operation_id] = link

    return Document(url=schema_url, title=title, content=content)