def validate(self, r, **attr):
        """
            Validate records (AJAX). This method reads a JSON object from
            the request body, validates it against the current resource,
            and returns a JSON object with either the validation errors or
            the text representations of the data.

            @param r: the S3Request
            @param attr: dictionary of parameters for the method handler

            Input JSON format:

            {"<fieldname>":"<value>", "<fieldname>":"<value>"}

            Output JSON format:

            {"<fieldname>": {"value":"<value>",
                             "text":"<representation>",
                             "_error":"<error message>"}}

            The input JSON can also be a list of multiple records. This
            will return a list of results accordingly. Note that "text"
            is not provided if there was a validation error, and vice
            versa.

            The record ID should always be present in the JSON to
            avoid false duplicate errors.

            Non-existent fields will return "invalid field" as _error.

            Representations will be URL-escaped and any markup stripped.

            The ?component=<alias> URL query can be used to specify a
            component of the current resource rather than the main table.

            This method does only accept .json format.
        """

        if r.representation != "json":
            r.error(415, current.ERROR.BAD_FORMAT)

        resource = self.resource

        get_vars = r.get_vars
        if get_vars in "component":
            alias = get_vars["component"]
        else:
            alias = None
        if "resource" in get_vars:
            tablename = get_vars["resource"]

            # Customise the resource
            customise = current.deployment_settings.customise_resource(tablename)
            if customise:
                customise(r, tablename)

            components = [alias] if alias else None
            try:
                resource = current.s3db.resource(tablename,
                                                 components=components)
            except:
                r.error(404, current.ERROR.BAD_RESOURCE)
        if alias:
            if alias in resource.components:
                component = resource.components[alias]
            else:
                r.error(404, current.ERROR.BAD_RESOURCE)
        else:
            component = resource

        source = r.body
        source.seek(0)

        try:
            data = json.load(source)
        except ValueError:
            r.error(501, current.ERROR.BAD_SOURCE)

        if not isinstance(data, list):
            single = True
            data = [data]
        else:
            single = False

        table = component.table
        pkey = table._id.name

        get_config = current.s3db.get_config
        tablename = component.tablename
        onvalidation = get_config(tablename, "onvalidation")
        update_onvalidation = get_config(tablename, "update_onvalidation",
                                         onvalidation)
        create_onvalidation = get_config(tablename, "create_onvalidation",
                                         onvalidation)

        output = []
        for record in data:

            has_errors = False

            # Retrieve the record ID
            if pkey in record:
                original = {pkey: record[pkey]}
            elif "_id" in record:
                original = {pkey: record["_id"]}
            else:
                original = None

            # Field validation
            fields = Storage()
            for fname in record:

                error = None
                validated = fields[fname] = Storage()

                # We do not validate primary keys
                # (because we don't update them)
                if fname in (pkey, "_id"):
                    continue

                value = record[fname]

                if fname not in table.fields:
                    validated["value"] = value
                    validated["_error"] = "invalid field"
                    continue
                else:
                    field = table[fname]

                # Convert numeric type (does not always happen in the widget)
                field = table[fname]
                if field.type == "integer":
                    if value not in (None, ""):
                        try:
                            value = int(value)
                        except ValueError:
                            value = 0
                    else:
                        value = None
                if field.type == "double":
                    if value not in (None, ""):
                        try:
                            value = float(value)
                        except ValueError:
                            value = 0
                    else:
                        value = None

                widget = field.widget
                if isinstance(widget, S3Selector):
                    # Use widget-validator instead of field-validator
                    value, error = widget.validate(value,
                                                   requires=field.requires,
                                                   )
                    validated["value"] = widget.serialize(value)
                    # Use widget-represent instead of standard represent
                    widget_represent = widget.represent
                else:
                    # Validate and format the value
                    try:
                        value, error = s3_validate(table, fname, value, original)
                    except AttributeError:
                        error = "invalid field"
                    validated["value"] = field.formatter(value)
                    widget_represent = None

                # Handle errors, update the validated item
                if error:
                    has_errors = True
                    validated["_error"] = s3_unicode(error)
                elif widget_represent:
                    try:
                        text = widget_represent(value)
                    except:
                        text = s3_unicode(value)
                    validated["text"] = text
                else:
                    try:
                        text = s3_represent_value(field, value = value)
                    except:
                        text = s3_unicode(value)
                    validated["text"] = text

            # Form validation (=onvalidation)
            if not has_errors:
                if original is not None:
                    onvalidation = update_onvalidation
                else:
                    onvalidation = create_onvalidation
                form = Storage(vars=Storage(record), errors=Storage())
                if onvalidation is not None:
                    callback(onvalidation, form, tablename=tablename)
                for fn in form.errors:
                    msg = s3_unicode(form.errors[fn])
                    if fn in fields:
                        validated = fields[fn]
                        has_errors = True
                        validated._error = msg
                        if "text" in validated:
                            del validated["text"]
                    else:
                        msg = "%s: %s" % (fn, msg)
                        if "_error" in fields:
                            fields["_error"] = "\n".join([msg,
                                                          fields["_error"]])
                        else:
                            fields["_error"] = msg

            output.append(fields)

        if single and len(output) == 1:
            output = output[0]

        return json.dumps(output, separators=SEPARATORS)

    # -------------------------------------------------------------------------
    # Utility functions
    # -------------------------------------------------------------------------
dataset/ETHPy150Open sahana/eden/modules/s3/s3crud.py/S3CRUD.validate/swapped operands of `in`