Compare a string with multiple JSON property values using JSONPath
I'm building a search suggestion text box control in JavaScript and am trying to find a way to compare the string the user typed against a JSON Object that represents the us开发者_如何学Cer's contact list.
The JSON Object looks like this:
var contacts = {
'gmail' : [
{ name : 'Joe Smith', email : 'joe.smith@gmail.com' },
{ name : 'James Simpson', email : 'jim.simpson@gmail.com' }
]
}
Using JSONPath, I've been able to successfully compare the string the user typed against a single field in the contact object (ie. I can test the name, or the email) using the following:
var input = "james";
var search_path = '$.*[?( /' + input + '/i.test(@.name))]';
var results = jsonPath(contacts ,search_path, {resultType:"VALUE"});
Which returns the {James Simpson}
contact object, but if I had typed Jim instead of James it would return nothing unless I did two separate JSONPath queries - one against the name and the other against the email.
What I'm looking is an elegant way to do an OR operator with JSONPath so I can test a single string against multiple JSON property values.
Here's the psuedo-code (non-working) that describes what I'm looking for:
var search_path = '$.*[?( /' + input + '/i.test([ @.name, @.email ]))]';
Does anyone know of a way to do this?
I would create a simpler data structure that maps search terms to a contact name. Once you have a contact name, look up the entire record using jsonPath
A better way is to use DefiantJS (http://defiantjs.com). This lib extends the global object JSON with the method "search" - with which you can query JSON structure with XPath expressions. This method returns the matches in an array (empty if no matches were found).
Here is a working JSfiddle of the code below;
http://jsfiddle.net/hbi99/z2Erf/
var data = {
"gmail": [
{
"name": "Joe Smith",
"email": "joe.smith@gmail.com"
},
{
"name": "James Simpson",
"email": "jim.simpson@gmail.com"
}
]
},
res = JSON.search( data, '//gmail[contains(., "jim")]' );
console.log( res[0].name );
// James Simpson
The expression '//gmail[contains(., "jim")]' will find all fields under GMAIL regardless of field name. To explicitly constrict the search to the fields "name" and "email", then the query should look like this:
'//gmail[contains(name, "jim") or contains(email, "jim")]'
To get an idea of how powerful XPath is, check out this XPath Evaluator tool;
http://www.defiantjs.com/#xpath_evaluator
If you are using Goessner's parser, you can use the ||
operator in your expression as follows:
var search_path = '$.*[?(/jim/i.test(@.name) || /jim/i.test(@.email))]';
精彩评论