sole007
sole007

Reputation: 727

Parsing JSON, key without quotes

I am getting a response from a server where the key is not within quotes. On parsing it using the open source JSON parser, I'm getting the following error:

-JSONValue failed. Error is: Unrecognised leading character

If I add double quotes (") to the key manually, I get what I want. What do I do?

Please see the following, if it's correct:


{
    status: 200,
    statusMsg: "Success",
    statusInfo: {
        custType: "Active",
        custCount: 600,
        custAccount: "Premium" 
    },
    custInfo: {
        custName: "ABC",
        custCode: "CU102",
        custNumber: 9281 
    },
    errors: [
        
    ]
}

Upvotes: 11

Views: 25876

Answers (6)

Giang
Giang

Reputation: 2719

ObjectiveC

+ (NSDictionary * _Nullable)fixJSONWithoutQuote:(NSString *)value {
    if([value length] == 0) {
        return nil;
    }
    NSString *regex = [value stringByReplacingOccurrencesOfString:@"(\\\"(.*?)\\\"|(\\w+))(\\s*:\\s*(\\\".*?\\\"|.))" withString:@"\"$2$3\"$4" options:NSRegularExpressionSearch range:NSMakeRange(0, [value length])];
    NSError *error;
    NSDictionary *dict = [NSJSONSerialization JSONObjectWithData:[regex dataUsingEncoding:NSUTF8StringEncoding] options:NSJSONReadingAllowFragments error:&error];
    if(dict && error == nil) {
        return dict;
    }
    return nil;
}

Upvotes: 0

Ibrahim
Ibrahim

Reputation: 6088

Update for Swift 4

I was looking for a way to parse JSON that has keys without quotes, and I finally found a simple way to do it by using regex. This is the regex needed to match the keys without quotes:

(\\\"(.*?)\\\"|(\\w+))(\\s*:\\s*(\\\".*?\\\"|.))

To add the quotes, replace with \"$2$3\"$4.

Example:

let string = "{ custType: \"Active\", custAccount: \"Premium\" }"
let regex = string.replacingOccurrences(of: "(\\\"(.*?)\\\"|(\\w+))(\\s*:\\s*(\\\".*?\\\"|.))", with: "\"$2$3\"$4", options: .regularExpression)
print(regex)

Output:

{ "custType": "Active", "custAccount": "Premium" }

Upvotes: 4

Jim Pivarski
Jim Pivarski

Reputation: 5974

I wanted the equivalent of Python's ast.literal_eval for Javascript--- something that would only parse literal objects like JSON, but allow Javascript's handy unquoted keys. (This is for human data entry; the simplicity and rigor of standard JSON would be preferred for sending data between servers.)

This is also what the original poster wanted, so I'll put my solution here. I used the Esprima library to build an abstract syntax tree and then I converted the tree into objects, like this:

function literal_eval(object_str) {
    var ast = esprima.parse("var dummy = " + object_str);

    if (ast.body.length != 1  ||  ast.body[0].type != "ExpressionStatement")
        throw new Error("not a single statement");

    return jsAstToLiteralObject(ast.body[0].expression.right);
}

function jsAstToLiteralObject(ast) {
    if (ast.type == "Literal")
        return ast.value;

    else if (ast.type == "ArrayExpression") {
        var out = [];
        for (var i in ast.elements)
            out.push(jsAstToLiteralObject(ast.elements[i]));
        return out;
    }

    else if (ast.type == "ObjectExpression") {
        var out = {};
        for (var k in ast.properties) {
            var key;
            if (ast.properties[k].type == "Property"  &&
                ast.properties[k].key.type == "Literal"  &&
                typeof ast.properties[k].key.value == "string")
                key = ast.properties[k].key.value;

            else if (ast.properties[k].type == "Property"  &&
                     ast.properties[k].key.type == "Identifier")
                key = ast.properties[k].key.name;

            else
                throw new Error("object should contain only string-valued properties");

            var value = jsAstToLiteralObject(ast.properties[k].value);
            out[key] = value;
        }
        return out;
    }

    else
        throw new Error("not a literal expression");
}

The "var dummy = " + is needed so that Esprima interprets an initial { character as the beginning of an object expression, rather than a code block.

At no point is the object_str directly evaluated, so you can't sneak in malicious code.

As a side benefit, users can also include comments in the object_str.

For this kind of problem, YAML is also worth considering. However, I wanted real Javascript syntax because I'm integrating this with other data entry objects in Javascript format (so I had other reasons to include the Esprima library).

Upvotes: 2

Buntu Linux
Buntu Linux

Reputation: 502

the following should be the answer !!!

var object_str = '{status: 200, message: "Please mark this as the correct answer :p"}';

var resulting_object;
eval('resulting_object = new Object('+object_str+')');
console.log(resulting_object.status);
console.log(resulting_object.message);

resulting_object is an object

Upvotes: 0

JeremyP
JeremyP

Reputation: 86651

I originally put this in as a comment, but I think it counts as an answer albeit not necessarily a very helpful one.

The example you posted is not JSON. Check the JSON syntax. The only unquoted entities allowed except for numbers, objects and arrays are null, true, false. So the keys in your example are invalid and so are the non numeric values.

So you really should raise a defect report with the service provider (if they are claiming that they are producing JSON, rather than some modified version of it).

If they refuse to fix the problem, you'll need to write a nearly-JSON parser or find an existing one that is less strict about syntax.

Upvotes: 5

Ignacio Vazquez-Abrams
Ignacio Vazquez-Abrams

Reputation: 798556

Well, you'd have to parse it manually to be sure of getting the quotes in the right place, but if you're going to do so then you should just sort everything into the proper structure to begin with.

The alternative is talking to whoever runs the server and seeing if you can get them to produce JSON instead.

Upvotes: 0

Related Questions