I had a JSON string / object in my application.
{"list": [
{"name":"my Name","id":12,"type":"car owner"},
{"name":"my Name2","id":13,"type":"car owner2"},
{"name":"my Name4","id":14,"type":"car owner3"},
{"name":"my Name4","id":15,"type":"car owner5"}
]}
I had a filter box in my application, and when I type a name into that box, we have to filter the object and display the result.
For example, if the user types “name” and hits search, then we have to search full names in the JSON object and return the array, just like a MySQL search …
My question is to filter the json object with string and return the array….
asked May 21, 2012 at 4:42
rameshramesh
3,97613 gold badges71 silver badges117 bronze badges
5
You could just loop through the array and find the matches:
var results = [];
var searchField = "name";
var searchVal = "my Name";
for (var i=0 ; i < obj.list.length ; i++)
{
if (obj.list[i][searchField] == searchVal) {
results.push(obj.list[i]);
}
}
answered May 21, 2012 at 4:49
McGarnagleMcGarnagle
101k31 gold badges226 silver badges259 bronze badges
0
If your question is, is there some built-in thing that will do the search for you, then no, there isn’t. You basically loop through the array using either String#indexOf
or a regular expression to test the strings.
For the loop, you have at least three choices:
-
A boring old
for
loop. -
On ES5-enabled environments (or with a shim),
Array#filter
. -
Because you’re using jQuery,
jQuery.map
.
Boring old for
loop example:
function search(source, name) {
var results = [];
var index;
var entry;
name = name.toUpperCase();
for (index = 0; index < source.length; ++index) {
entry = source[index];
if (entry && entry.name && entry.name.toUpperCase().indexOf(name) !== -1) {
results.push(entry);
}
}
return results;
}
Where you’d call that with obj.list
as source
and the desired name fragment as name
.
Or if there’s any chance there are blank entries or entries without names, change the if
to:
if (entry && entry.name && entry.name.toUpperCase().indexOf(name) !== -1) {
Array#filter
example:
function search(source, name) {
var results;
name = name.toUpperCase();
results = source.filter(function(entry) {
return entry.name.toUpperCase().indexOf(name) !== -1;
});
return results;
}
And again, if any chance that there are blank entries (e.g., undefined
, as opposed to missing; filter
will skip missing entries), change the inner return to:
return entry && entry.name && entry.name.toUpperCase().indexOf(name) !== -1;
jQuery.map
example (here I’m assuming jQuery
= $
as is usually the case; change $
to jQuery
if you’re using noConflict
):
function search(source, name) {
var results;
name = name.toUpperCase();
results = $.map(source, function(entry) {
var match = entry.name.toUpperCase().indexOf(name) !== -1;
return match ? entry : null;
});
return results;
}
(And again, add entry && entry.name &&
in there if necessary.)
answered May 21, 2012 at 4:48
T.J. CrowderT.J. Crowder
1.0m187 gold badges1903 silver badges1862 bronze badges
6
You can simply save your data in a variable and use find(to get single object of records) or filter(to get single array of records) method of JavaScript.
For example :-
let data = {
"list": [
{"name":"my Name","id":12,"type":"car owner"},
{"name":"my Name2","id":13,"type":"car owner2"},
{"name":"my Name4","id":14,"type":"car owner3"},
{"name":"my Name4","id":15,"type":"car owner5"}
]}
and now use below command onkeyup or enter
to get single object
data.list.find( record => record.name === "my Name")
to get single array object
data.list.filter( record => record.name === "my Name")
Ejaz47
1451 silver badge12 bronze badges
answered Feb 5, 2020 at 4:15
Anand Deep SinghAnand Deep Singh
2,5173 gold badges22 silver badges28 bronze badges
Use PaulGuo’s jSQL, a SQL like database using javascript. For example:
var db = new jSQL();
db.create('dbname', testListData).use('dbname');
var data = db.select('*').where(function(o) {
return o.name == 'Jacking';
}).listAll();
answered May 21, 2012 at 5:12
I adapted regex to work with JSON.
First, stringify the JSON object. Then, you need to store the starts and lengths of the matched substrings. For example:
"matched".search("ch") // yields 3
For a JSON string, this works exactly the same (unless you are searching explicitly for commas and curly brackets in which case I’d recommend some prior transform of your JSON object before performing regex (i.e. think :, {, }).
Next, you need to reconstruct the JSON object. The algorithm I authored does this by detecting JSON syntax by recursively going backwards from the match index. For instance, the pseudo code might look as follows:
find the next key preceding the match index, call this theKey
then find the number of all occurrences of this key preceding theKey, call this theNumber
using the number of occurrences of all keys with same name as theKey up to position of theKey, traverse the object until keys named theKey has been discovered theNumber times
return this object called parentChain
With this information, it is possible to use regex to filter a JSON object to return the key, the value, and the parent object chain.
You can see the library and code I authored at http://json.spiritway.co/
answered Mar 27, 2015 at 19:36
1
If you are doing this in more than one place in your application it would make sense to use a client-side JSON database because creating custom search functions that get called by array.filter() is messy and less maintainable than the alternative.
Check out ForerunnerDB which provides you with a very powerful client-side JSON database system and includes a very simple query language to help you do exactly what you are looking for:
// Create a new instance of ForerunnerDB and then ask for a database
var fdb = new ForerunnerDB(),
db = fdb.db('myTestDatabase'),
coll;
// Create our new collection (like a MySQL table) and change the default
// primary key from "_id" to "id"
coll = db.collection('myCollection', {primaryKey: 'id'});
// Insert our records into the collection
coll.insert([
{"name":"my Name","id":12,"type":"car owner"},
{"name":"my Name2","id":13,"type":"car owner2"},
{"name":"my Name4","id":14,"type":"car owner3"},
{"name":"my Name4","id":15,"type":"car owner5"}
]);
// Search the collection for the string "my nam" as a case insensitive
// regular expression - this search will match all records because every
// name field has the text "my Nam" in it
var searchResultArray = coll.find({
name: /my nam/i
});
console.log(searchResultArray);
/* Outputs
[
{"name":"my Name","id":12,"type":"car owner"},
{"name":"my Name2","id":13,"type":"car owner2"},
{"name":"my Name4","id":14,"type":"car owner3"},
{"name":"my Name4","id":15,"type":"car owner5"}
]
*/
Disclaimer: I am the developer of ForerunnerDB.
answered Dec 7, 2016 at 15:34
Rob EvansRob Evans
6,7404 gold badges38 silver badges56 bronze badges
0
Here is an iterative solution using object-scan. The advantage is that you can easily do other processing in the filter function and specify the paths in a more readable format. There is a trade-off in introducing a dependency though, so it really depends on your use case.
// const objectScan = require('object-scan');
const search = (haystack, k, v) => objectScan([`list[*].${k}`], {
rtn: 'parent',
filterFn: ({ value }) => value === v
})(haystack);
const obj = { list: [ { name: 'my Name', id: 12, type: 'car owner' }, { name: 'my Name2', id: 13, type: 'car owner2' }, { name: 'my Name4', id: 14, type: 'car owner3' }, { name: 'my Name4', id: 15, type: 'car owner5' } ] };
console.log(search(obj, 'name', 'my Name'));
// => [ { name: 'my Name', id: 12, type: 'car owner' } ]
.as-console-wrapper {max-height: 100% !important; top: 0}
<script src="https://bundle.run/object-scan@13.8.0"></script>
Disclaimer: I’m the author of object-scan
answered Nov 18, 2020 at 5:58
vincentvincent
1,8833 gold badges17 silver badges24 bronze badges
You can filter json object using any value from any property using this library
Js-Search
answered Jun 3, 2022 at 19:58
Cyber ProgsCyber Progs
3,5863 gold badges29 silver badges39 bronze badges
You can try this:
function search(data,search) {
var obj = [], index=0;
for(var i=0; i<data.length; i++) {
for(key in data[i]){
if(data[i][key].toString().toLowerCase().indexOf(search.toLowerCase())!=-1) {
obj[index] = data[i];
index++;
break;
}
}
return obj;
}
console.log(search(obj.list,'my Name'));
bfontaine
17.8k13 gold badges71 silver badges103 bronze badges
answered Oct 19, 2017 at 9:20
0
As my opening contribution, i leave here a method i developed to search inside a JSON object for a specific value (could be or not the name of the object property).
https://gist.github.com/killants/569c4af5f2983e340512916e15a48ac0
I’ll be happy if at least one person finds it usefull.
Feel free to edit and improve it! Any feedback is welcome!
Top comments (13)
Collapse
Expand
Without changing the structure, I would do the following:
const charSeparator = "/"
/**
* searches deep into an object recursively...
* @param {Object} obj object to be searched
* @param {any} searchValue the value/key to search for
* @param {boolean} [valuesOnly=false] whether to skip comparing object keys
* @param {number} [maxDepth=20] maximum recursion depth (to avoid "Maximum call stack size exceeded")
* @returns {string[]} Paths on the object to the matching results
*/
function getValuePathInObject(
obj,
searchValue,
valuesOnly = false,
maxDepth = 20
) {
if (!maxDepth) return []
const paths = []
for (const [curr, currElem] of Object.entries(obj)) {
if (!valuesOnly && curr === searchValue) {
// To search for property name too...
paths.push(curr)
}
if (typeof currElem == "object") {
// object is "object" and "array" is also in the eyes of `typeof`
// search again :D
const deepPaths = getValuePathInObject(
currElem,
searchValue,
valuesOnly,
maxDepth - 1
)
const currDir = curr + charSeparator
for (const path of deepPaths) {
paths.push(currDir + path)
}
continue
}
// it's something else... probably the value we are looking for
// compares with `searchValue`
if (currElem === searchValue) {
// return index AND/OR property name
paths.push(curr)
}
}
return paths
}
- Use
const
andlet
, nevervar
. - Use
for of
loops instead of imperative key and numeric index iteration. - Remove the debug logging
- Hoist the constant
charSeparator
out of the function (or you could inline the"/"
literal) - Only concatenate
curr
andcharSeparator
once, not in the loop. - Remove unused variable
i
. - Use early return (or rather,
continue
). - Use JSDoc, LMAO xD
- Use down-counting depth limit to pass only one number.
- Use defaults in the function parameters. These only check for
undefined
, not truthiness, so passingfalse
and0
won’t trigger them.
Collapse
Expand
Otherwise, I’d use an inner recursive function so that I can do option parsing once, and then close over one array I will always append to, to avoid allocating intermediate arrays:
/**
* searches deep into an object recursively...
* @param {Object} obj object to be searched
* @param {any} searchValue the value/key to search for
* @param {Object} [options]
* @param {boolean} options.[searchKeys] whether to search object keys as well as values. Defaults to `true` if `serchValue` is a string, `false` otherwise.
* @param {number} options.[maxDepth=20] maximum recursion depth (to avoid "Maximum call stack size exceeded")
* @returns {string[]} Paths on the object to the matching results
*/
const findPaths = (
obj,
searchValue,
{ searchKeys = typeof searchValue === "string", maxDepth = 20 } = {}
) => {
const paths = []
const notObject = typeof searchValue !== "object"
const gvpio = (obj, maxDepth, prefix) => {
if (!maxDepth) return
for (const [curr, currElem] of Object.entries(obj)) {
if (searchKeys && curr === searchValue) {
// To search for property name too ...
paths.push(prefix + curr)
}
if (typeof currElem === "object") {
// object is "object" and "array" is also in the eyes of "typeof"
// search again :D
gvpio(currElem, maxDepth - 1, prefix + curr + "/")
if (notObject) continue
}
// it's something else... probably the value we are looking for
// compares with "searchValue"
if (currElem === searchValue) {
// return index AND/OR property name
paths.push(prefix + curr)
}
}
}
gvpio(obj, maxDepth, "")
return paths
}
Here, I’m also using an options object for convenience, with a smart default for searchKeys
, since object keys are always strings, even in arrays:
console.log(findPaths([[[]],[[]]],0)) // []
console.log(findPaths([[[]],[[]]],'0')) // [ '0', '0/0', '1/0' ]
I’m also building the path
string with no duplication. This includes eliminating the inner loop, since we never return an intermediary array back up. The reason prefix + curr
occurs in 3 places is because in a real search, on most keys none of those conditions will happen, and almost never will two happen together.
Collapse
Expand
Finally, at the cost of a tiny bit of memory, you can keep a Set
of visited objects so you can prevent infinite recursion without a counter.
Before:
const obj = {
a: 0,
b: 1,
c: [[]]
}
const obj2 = {t:obj}
obj.c[0].push(obj2, 't')
console.log(findPaths(obj,"t"));
[ 'c/0/0/t',
'c/0/0/t/c/0/0/t',
'c/0/0/t/c/0/0/t/c/0/0/t',
'c/0/0/t/c/0/0/t/c/0/0/t/c/0/0/t',
'c/0/0/t/c/0/0/t/c/0/0/t/c/0/0/t/c/0/0/t',
'c/0/0/t/c/0/0/t/c/0/0/t/c/0/0/t/c/0/1',
'c/0/0/t/c/0/0/t/c/0/0/t/c/0/1',
'c/0/0/t/c/0/0/t/c/0/1',
'c/0/0/t/c/0/1',
'c/0/1' ]
After:
Output:
Code:
/**
* searches deep into an object recursively...
* @param {Object} obj object to be searched
* @param {any} searchValue the value/key to search for
* @param {boolean} [searchKeys] whether to search object keys as well as values. Defaults to `true` if `serchValue` is a string, `false` otherwise.
* @returns {string[]} Paths on the object to the matching results
*/
const findPaths = (
obj,
searchValue,
searchKeys = typeof searchValue === "string"
) => {
const paths = []
const visited = new Set()
const notObject = typeof searchValue !== "object"
const gvpio = (obj, prefix) => {
for (const [curr, currElem] of Object.entries(obj)) {
if (searchKeys && curr === searchValue) {
paths.push(prefix + curr)
}
if (typeof currElem === "object") {
if (visited.has(currElem)) continue
visited.add(currElem)
gvpio(currElem, prefix + curr + "/")
if (notObject) continue
}
if (currElem === searchValue) {
paths.push(prefix + curr)
}
}
}
gvpio(obj, "")
return paths
}
Disclaimer:
Be careful though, it won’t always include the shortest path!
const obj = {
t: "t"
}
const obj2 = {
a: [{ a: [{ a: [{ obj }] }] }],
b: obj
}
console.log(findPaths(obj2, "t"));
[ 'a/0/a/0/a/0/obj/t', 'a/0/a/0/a/0/obj/t' ] // :(
Collapse
Expand
Not used to see many arrow function (without being small ones, in array.map for example) so i got a bit confused with the parameter line :
{ searchKeys = typeof searchValue === “string”, maxDepth = 20 } = {}
Would you mind to explain in a few words why it is there? 🙂
Thank you in advance.
Sure, this doesn’t depend on it being an arrow function, can be in a function
just as well.
This is the equivalent function:
function fn(arg) {
if (arg === undefined) arg = {}
let searchKeys = arg.searchKeys
if (searchKeys === undefined) searchKeys = typeof searchValue === "string"
let maxDepth = arg.maxDepth
if (maxDepth === undefined) maxDepth = 20
/* ... */
}
First, we replace the point access with destructuring:
function fn(arg) {
if (arg === undefined) arg = {}
let { searchKeys, maxDepth } = arg
if (searchKeys === undefined) searchKeys = typeof searchValue === "string"
if (maxDepth === undefined) maxDepth = 20
/* ... */
}
Next, we replace the conditional expressions for defaults with defaults in destructuring AND default in parameter:
function fn(arg = {}) {
const { // we can use const now because we won't be reassigning
searchKeys = typeof searchValue === "string",
maxDepth = 20
} = arg
/* ... */
}
Finally, to avoid having to think of a name for the short-lived arg
binding, we can just YEET it right into the parameter list:
function fn({
searchKeys = typeof searchValue === "string",
maxDepth = 20
} = {}) {
/* ... */
}
We could write it like this:
function fn(
{
searchKeys = typeof searchValue === "string",
maxDepth = 20
} = {
searchKeys: typeof searchValue === "string",
maxDepth: 20
}
) {
/* ... */
}
But that’s just more verbose. Destructuring an empty object (if undefined
is provided) is perfectly adequate, and gives defaults for all keys.
function fn(
searchValue, // this is the v below that we are depending on, it has to come first.
{ searchKeys = typeof searchValue === "string", maxDepth = 20 } = {}
) {
/* ... */
}
Collapse
Expand
killants
I’m a developer at a business solution company. Main activities are JavaScript and Hana DB.
-
Location
Óbidos, Portugal
-
Work
Developer at NewOxygen
-
Joined
Jan 31, 2019
•
Feb 4 ’19
- Copy link
Hasn’t use “let” before to declare variables, will definitely use now ( Thanks to Sarah Chima for her post “dev.to/sarah_chima/var-let-and-con…” )! 😀
Is “for of” more optimized for this kind of methods (recursive), instead of indexed ones ?
I had that “charSeparator” declared inside because at the time i made it i though leaving the option to choose the char used to be received in parameter (but then i just forgot it XD)
That variable “i” …. I just can’t even remember why was there ?? :/ My bad !
Tonight i won’t be able, but tomorrow right after work, will fix it ! 😉
Thanks a lot for your feedback Mihail 😀
Collapse
Expand
If you look in the replies to my above comment, I replied to myself (and then replied again to that comment) with new versions of the code.
Collapse
Expand
I had a similar idea last year 🙂 Take a look at object-scan
and the filterFn function. Shows where requirements ultimately go haha
Collapse
Expand
killants
I’m a developer at a business solution company. Main activities are JavaScript and Hana DB.
-
Location
Óbidos, Portugal
-
Work
Developer at NewOxygen
-
Joined
Jan 31, 2019
•
May 27 ’19
- Copy link
a look where ? sorry not finding “object-scan” as told… Would you mind sharing a link, please?
Thanks
Collapse
Expand
Collapse
Expand
killants
I’m a developer at a business solution company. Main activities are JavaScript and Hana DB.
-
Location
Óbidos, Portugal
-
Work
Developer at NewOxygen
-
Joined
Jan 31, 2019
•
Feb 4 ’19
- Copy link
I added to the gist, the optimized function provided by “Mihail Malostanidis” (dev.to/qm3ster) since it is way more “clean”. I leaved the old one so you can compare with my first attempt and see the difference. You can always check Mihail comments on this post since he explains his approach to this.
Big thanks to Mihail for his help!!! 🙂
Collapse
Expand
Was a fully single-recursive implementation part of the goal?
Collapse
Expand
killants
I’m a developer at a business solution company. Main activities are JavaScript and Hana DB.
-
Location
Óbidos, Portugal
-
Work
Developer at NewOxygen
-
Joined
Jan 31, 2019
•
Feb 4 ’19
- Copy link
Was my way of thinking, i made this method just to fecth the path in some object which value i knew it exists somewhere. 🙂
For further actions, you may consider blocking this person and/or reporting abuse
JSON означает JavaScript Object Notation. JSON — это чрезвычайно легкий формат обмена данными между сервером и клиентом, который можно быстро и легко анализировать и генерировать.
Как и XML, JSON также является текстовым форматом, который легко написать и легко понять как для людей, так и для компьютеров, но в отличие от XML структуры данных JSON занимают меньшую пропускную способность, чем их версии XML. JSON основан на двух основных структурах:
- Объект: он определяется как неупорядоченная коллекция пар ключ / значение (
key:value
). Каждый объект начинается с левой фигурной скобки{
и заканчивается правой фигурной скобкой}
. Несколько пар ключ / значение разделяются запятой,
. - Массив: он определяется как упорядоченный список значений. Массив начинается с левой скобки
[
и заканчивается правой скобкой]
. Значения разделяются запятой,
.
В JSON имена свойств или ключи всегда являются строками, а значение может быть string
, number
, true
или false
, null
и даже object
или array
. Строки должны быть заключены в двойные кавычки "
и могут содержать управляющие символы, такие как n
, t
и . Объект JSON может выглядеть следующим образом:
{
"book": {
"name": "Harry Potter and the Goblet of Fire",
"author": "J. K. Rowling",
"year": 2000,
"genre": "Fantasy Fiction",
"bestseller": true
}
}
Пример массива JSON будет выглядеть примерно так:
{
"fruits": [
"Apple",
"Banana",
"Strawberry",
"Mango"
]
}
JSON — это самый популярный и легкий текстовый формат обмена данными между различными платформами и операционными системами.
В JavaScript вы можете легко анализировать данные JSON, полученные с веб-сервера, используя метод JSON.parse()
. Этот метод анализирует строку JSON и создает значение JavaScript или объект, описываемый строкой. Если данная строка не является допустимой JSON, вы получите синтаксическую ошибку.
Предположим, мы получили следующую JSON-кодированную строку с веб-сервера:
{"name": "Peter", "age": 22, "country": "United States"}
Теперь мы можем просто использовать метод JavaScript JSON.parse()
, чтобы преобразовать эту строку JSON в объект JavaScript и получить доступ к отдельным значениям с помощью точечной нотации (.
), Например:
// Получаем данные JSON в переменную
var json = '{"name": "Peter", "age": 22, "country": "United States"}';
// Преобразуем JSON в объект JS
var obj = JSON.parse(json);
// Доступ к индивидуальному значению из объекта JS
alert(obj.name); // Вывод: Peter
alert(obj.age); // Вывод: 22
alert(obj.country); // Вывод: United States
Пожалуйста, ознакомьтесь с руководством по синтаксическому анализу PHP JSON, чтобы узнать, как в ответ возвращать данные JSON с веб-сервера, а также как кодировать / декодировать данные JSON на стороне сервера с использованием PHP.
Разбор вложенных данных JSON в JavaScript
Объекты и массивы JSON также могут быть вложенными. Объект JSON может произвольно содержать другие объекты JSON, массивы, вложенные массивы, массивы объектов JSON и т. д. В следующем примере показано, как проанализировать вложенный объект JSON и извлечь все значения в JavaScript.
/* Хранение многострочной строки JSON в переменной JS
используя новые литералы шаблона ES6 */
var json = `{
"book": {
"name": "Harry Potter and the Goblet of Fire",
"author": "J. K. Rowling",
"year": 2000,
"characters": ["Harry Potter", "Hermione Granger", "Ron Weasley"],
"genre": "Fantasy Fiction",
"price": {
"paperback": "$10.40", "hardcover": "$20.32", "kindle": "$4.11"
}
}
}`;
// Преобразование объекта JSON в объект JS
var obj = JSON.parse(json);
// Рекурсивная функция для печати вложенных значений
function printValues(obj) {
for(var k in obj) {
if(obj[k] instanceof Object) {
printValues(obj[k]);
} else {
document.write(obj[k] + "<br>");
};
}
};
// Печать всех значений из результирующего объекта
printValues(obj);
document.write("<hr>");
// Печать одного значения
document.write(obj["book"]["author"] + "<br>"); // Выводит: J. K. Rowling
document.write(obj["book"]["characters"][0] + "<br>"); // Выводит: Harry Potter
document.write(obj["book"]["price"]["hardcover"]); // Выводит: $20.32
Кодирование данных как JSON в JavaScript
Иногда объект JavaScript или значение из вашего кода необходимо передавать на сервер во время Ajax. JavaScript предоставляет для этой цели метод JSON.stringify()
, который преобразует значение JavaScript в строку JSON, как показано ниже:
Stringify-объект JavaScript
В следующем примере показано, как преобразовать объект JavaScript в строку JSON:
// Образец объекта JS
var obj = {"name": "Peter", "age": 22, "country": "United States"};
// Преобразование объекта JS в строку JSON
var json = JSON.stringify(obj);
alert(json);
Хотя объекты JavaScript и JSON выглядят очень похоже, но они не совсем одинаковы. Например, в JavaScript имена свойств объекта могут быть заключены в одинарные кавычки ('...'
), двойные кавычки ("..."
) или же вы можете вообще опустить кавычки. Но в JSON все имена свойств должны быть заключены в двойные кавычки.
Stringify-массив JavaScript
Точно так же вы можете конвертировать массивы JavaScript в строки JSON, например:
// Образец массива JS
var arr = ["Apple", "Banana", "Mango", "Orange", "Papaya"];
// Преобразование массива JS в строку JSON
var json = JSON.stringify(arr);
alert(json);
Не используйте функцию eval()
для оценки данных JSON (включая определения функций в строке JSON и преобразование их обратно в исполняемые функции с помощью метода eval()
), поскольку это позволит злоумышленнику внедрить вредоносный код JavaScript в ваше приложение.
Похожие посты
- 24 декабря, 2019
- 988
Сортировка — обычная задача при работе с массивами. Она будет использоваться, например, если вы захотите отобразить названия городов или регионов в алфавитном порядке. JavaScript массив (array) имеет встроенный метод sort() для сортировки элементов массива в алфавитном порядке. Следующий пример демонстрирует, как это работает: Реверсирование массива Вы можете использовать метод reverse(), чтобы изменить порядок элементов массива…
- 17 декабря, 2019
- 642
Массивы — это сложные переменные, которые позволяют нам хранить группы значений под одним именем переменной. Массивы JavaScript могут хранить любое допустимое значение, включая строки, числа, объекты, функции и даже другие массивы, что позволяет создавать более сложные структуры данных, такие как массив объектов или массив массивов. Предположим, вы хотите сохранить название цветов в своем коде JavaScript….
- 15 декабря, 2019
- 282
Атрибуты — это специальные слова, используемые внутри начального тега HTML-элемента для управления поведением тега или предоставления дополнительной информации о теге. JavaScript предоставляет несколько методов для добавления, удаления или изменения атрибутов HTML-элемента. В этом разделе мы узнаем об этих методах подробно. Получение значения атрибута элемента Метод getAttribute() используется для получения текущего значения атрибута элемента. Если указанный…
Традиционно начну с небольшого вступления: речь в статье пойдет о том, как достать нужные данные из JSON, используя библиотеку JsonPath, которая входит в состав Rest Assured – наиболее популярного решения для тестирования API. Есть и другие одноименные библиотеки (JsonPath), которые используют другой синтаксис, это даже специально подчеркнули в доках Rest Assured во избежание путаницы.
JsonPath основан на Groovy Gpath и использует его для построения своих запросов, условно можно сказать, что это xpath для json – язык запросов для получения нужных данных. К сожалению не все из нас владеют Груви (я совсем не знаю), а вот нормальной документации по использованию языка запросов JsonPath в более-менее развернутом виде я не нашел. Вот доки GPath в груви, на котором все работает, вот доки самого класса с парой примеров, и конечно документация Rest-Assured
Итак, мы не рассматриваем, что такое JSON, как пользоваться Rest-Assured, какие методы есть в JsonPath для парсинга, вытягивания Листа или Мапы, начинаем сразу с того, что у нас есть некий json, из которого мы хотим получить различные данные. При этом нам не хочется или нет надобности создавать простые Java-классы и маппить данные из json на них, мы просто хотим вытащить необходимое просто и быстро, без написания лишнего кода. Библиотека JsonPath хоть и поставляется в составе RA, но может быть использована отдельно. Для тренировки или проверки, можете подтянуть зависимость
<dependency> <groupId>io.rest-assured</groupId> <artifactId>json-path</artifactId> <version>3.3.0</version> </dependency>
Ну а сам код для простоты будет вот таким
String expr = ""; // тут будет запрос System.out.println(JsonPath.from(json).getString(expr)); //выводим результат
Еще раз подчеркну, что мы не рассматриваем методы типа setRoot, getList, getMap и так далее, сосредоточимся на языке запросов. Вот json с которым мы будем работать:
{ "class": [ { "name": "Ivan", "surname": "Ivanov", "age": "13", "marks": [2,3,4,4,5], "address": { "street": "Lenin", "house": 12 } }, { "name": "Petr", "surname": "Petrov", "age": "14", "marks": [5,5,3,5], "address": { "street": "Marx", "house": 7 } }, { "name": "Ivan", "surname": "Sidorov", "age": "14", "marks": [3,4,2,2,3], "address": { "street": "Pobedy", "house": 9 }, "some.value": 42 }] }
Он составлен в учебных целях, для примера некоторых особенностей, обратите внимание, что возраст возвращается строкой («age»: «14»), а не числом, и, кроме того, у третьего ученика в классе есть уникальное поле «some.value»: 42 , которое тоже добавлено специально.
1.Начнем с самого простого – корень, индексы, точки
$ — корень нашего json, просто выведет его целиком (то, что внутри главных скобок{}), как и при использовании пустой строки
Значение любого поля можно получить указав его ключ, но поиск начинается от корня, потому если поле вложенное, то нужно указать путь до него с использованием точки корень.поле1.поле2
class – вернет список из трех объектов-учеников, это единственное поле в корне нашего json, все остальные данные уже вложены в него, поэтому путь к ним нужно будет начинать с указания “class”. Если, например написать “name” то нам вернет null, так как в корне нет такого ключа. Вообще такой подход аналогичен работе с XPath – начинаем от корня и двигаемся к искомой информации вглубь документа.
Работа со списком (массивом) аналогично Java с некоторыми замечаниями – первый индекс привычно 0, выходить за границы списка нельзя, но можно использовать отрицательные индексы и слайсинг как в питоне.
Важно! Все эти операции (индекс, слайсинг) применимы и к строке!
class[0] – вернет нам первый объект-ученик, а именно Иванова Ваню
class[-1] – вернет нам последний элемент списка то есть объект Сидорова Вани, аналог “class[2]”
class[-2] — вернет предпоследний элемент списка (и так далее до выхода за пределы массива), то есть Петрова. Такой же результат даст вызов “class[1]”
class[0..1] – вырежет из списка и вернет элементы ОТ нулевого (по индексу) ДО первого включительно, то есть вернет 2 первых объекта списка — Иванова и Петрова
class[1..2] – вернет последние два (для конкретно этого списка) объекта
Продолжаем погружение :
class[0].surname – получаем значение поля surname у самого первого объекта в списке, то есть получим “Ivanov”
class.name – вернет ВСЕ имена ([Ivan, Petr, Ivan]), то есть поля name у всех объектов списка. Обращаю внимание, что мы не указали никаких индексов, поэтому берется весь список и у каждого элемента ищется поле name. Если у какого-то из объектов такого поля нет — вмеcто него будет null, но в любом случае вернется список – это важно понимать.
class[0].address.house – вернет 12, то есть номер дома Вани Иванова. И так далее, используя индексы и точку можно двигаться вглубь структуры к любому из полей
Важно! Попробуем получить уникальное поле some.value из последнего объекта, навскидку это
class[-1].some.value – ожидали 42, но получаем нулл! Дело в том, что ключ содержит точку и при стандартной записи GPath считает, что должно быть поле some, а в него вложено поле value, не находит его и возвращает нулл. Вот как нужно поступать в таких случаях:
class[-1].’some.value’ – использование апострофа экранирует ключ и подсказывает, что точка в данном случае –часть названия, возвращает искомые 42
Но это все были простые случаи перемещения по иерархии, а в жизни нам чаще всего нужно искать данные порядок которых не известен или меняется. Для этого нужно использовать сложные запросы в стиле
2. Операция {it.поле условие}
class.find {it.name == ‘Ivan’} – вернет нам первый объект в котором есть поле name со значением Ivan, обратите внимание, что имя указано в апострофах, так как это строка, а не число.
Важно! it – это внутренняя переменная, которую генерирует Gpath, как итератор, она поочередно получает значения всех объектов, которые есть на данном уровне. То есть, для примера выше, будут перебираться все объекты-ученики, вложенные в class и у них будет проверяться поле name
class.findAll {it.name == ‘Ivan’} – почти то же самое, но вернется список ВСЕХ объектов, удовлетворяющих условию. Думаю вы легко проведете аналогию с некоторыми методами вебдрайвера – возвращает первый элемент, возвращает все. Условия конечно могут быть не только равенство, но и неравенство «!=» и больше, меньше, все как в Java.
Важно! Строка в Груви – это сравниваемый объект, к ней применимы операторы «>», «<», а также некоторые функции, которые в Java ассоциируются с числами и к строке не применимы!
class.findAll {it.name > ‘Ivan’} — вернет не ошибку, а объект Петрова Пети, потому что имя Petr>Ivan, буква P стоит дальше по алфавиту, чем I.
Если условие в фигурных скобках не указать, оставив лишь поле, то вернутся все элементы, где есть данное поле
class.findAll {it.name} — вернет все объекты, так как условия нет, а поле name есть у каждого
class.findAll {it.’some.value’} -вернет только Сидорова, так как поле some.value есть только у него
Теперь рассмотрим более интересные функции и запросы.
3. Стандартные математические функции min(), max(), sum()
Применимы только к спискам, содержащим числа или строки, причем сумма для строк вернет конкатенацию
class[0].marks.min() – получаем минимальную оценку первого объекта в списке (Иванов), к сожалению это 2.
class.address.house.max() — получаем максимальный номер дома среди всех учеников, вернет 12 – дом Иванова
К функциям min/max можно также применить выражение {it.поле} для нахождения элемента.
class.max {it.address.house} — вернет объект Иванова, так как у него самый большой номер дома. Важнейшая разница тут в том, что возвращается не само максимальное значение, а объект, который его содержит, что нужно чаще всего.
class.address.street.sum() -вернет конкатенацию названий улиц всех учеников то есть LeninMarxPobedy, так как улицы — это строки
class[-1].marks.sum() — вернет сумму оценок последнего ученика, то есть 14
Попробуем получить сумму всех оценок всех учеников:
class.marks.sum() — вместо ожидаемого числа, получаем список всех оценок [2, 3, 4, 4, 5, 5, 5, 3, 5, 3, 4, 2, 2, 3]! Это происходит из-за того, что class.marks вернет нам список списков или двумерный массив [[2, 3, 4, 4, 5], [5, 5, 3, 5], [3, 4, 2, 2, 3]] и операция суммирования в таком случае просто соберет все элементы в один список. Выходом будет или еще раз применить суммирование или сделать структуру данных плоской, используя flatten() функцию
class.marks.flatten().sum() — вернет ожидаемое число 50 и , на мой взгляд, читаемей, чем аналог «class.marks.sum().sum()»
4. Общие функции
size() – функция, возвращающая размер (количество полей, элементов, букв), применима к строке, списку, объекту. При этом для строки вернет количество букв, для списка количество элементов, для объекта количество полей. Не применимо к числу!
class.size() — ожидаемо вернет 3, то есть количество учеников в списке
class[0].name.size() — вернет 4, то есть количество букв в слове Ivan(поле name первого элемента)
class[0].address.size() — вернет 2, то есть количество полей в объекте адрес (улица, дом) у первого ученика
unique() – функция, которая возвращает только уникальные элементы, применима только к спискам.
class.name.unique() — вернет список из двух уникальных имен, так как у нас два Ивана [Ivan, Petr]
class.unique() — вернет все 3 наших ученика, так как все они уникальны
class.marks.flatten().unique() — вернет список уникальных оценок [2, 3, 4, 5], например, чтобы убедиться, что никто из ребят не получал 1
5. Всем известные функции работы со строками endsWith, startsWith, contains
class.findAll {it.surname.endsWith(‘rov’)} — получим список всех учеников, у которых фамилия заканчивается на «ров», то есть Петрова и Сидорова
class.findAll {it.name.startsWith(‘I’)} — список всех, у кого имя начинается на I, то есть Сидорова и Иванова (у обоих имя Ivan)
class.findAll {it.name.contains(‘e’)} — вернет того, у кого в имени есть «е», то есть Петра Петрова
Важно! Функция contains применима и к спискам:
class.findAll {it.marks.contains(2)} — вернет нам список двоечников, обратите внимание, что двойка без апострофов, так как оценки -это числа, а не строки
! – в значении НЕ применим к условиям, скажем если мы хотим увидеть кто у нас в классе еще не получал двоек
class.findAll {! it.marks.contains(2)} — вернет только Петрова, обратите внимание на восклицательный знак!
6. Функции преобразования.
Могут быть полезны в редких случаях, так как в основном при работе с json мы читаем данные, а не преобразовываем их. Вообще, как я понимаю тут можно использовать любые функции Груви, но далеко не все они нужны.
reverse() – разворот, применимо к спискам и строкам
class[0].marks.reverse() — вернет [5, 4, 4, 3, 2] то есть перевернутый список оценок первого ученика
class[1].name.reverse() — вернет rteP, то есть перевернутое имя второго ученика
toInteger() – применимо к строкам, возвращает число из строки
class[0].age.toInteger() -вернет 13, то есть возраст первого ученика, но не строкой, а числом. Ниже будет более полезный пример использования данной функции
Collect – функция преобразования данных и сбора их в список,
class.collect {it.name.toUpperCase()} — просто как пример преобразования полученных результатов, вернет все имена из заглавных букв [IVAN, PETR, IVAN]
class.collect {it.age.toInteger()} — вернет список всех возрастов [13, 14, 14], причем это список именно чисел, а не строк! Скажем, если мы хотим найти максимальный возраст
class.collect {it.age.toInteger()}.max() — вернет 14, верный ответ
Почему в данном случае нельзя использовать «class.age.max()»? Потому что в нашем случае это строки, а они сравниваются по алфавиту, а не как числа и если скажем поправить возраст одного из учеников на «4», то максимум вернет именно его, так как 4 стоит в алфавите дальше «1».
Если мы хотим найти самого младшего в классе, с учетом того, что возраст – строка
class.min {it.age.toInteger()} -вернет нам Иванова, которому 13
Еще обращаю внимание, что операции не терминальные, после поиска или преобразования мы можем еще применить функцию или перейти к полю
class.find {it.name.endsWith(‘an’)}.marks[-1] — получаем последнюю оценку первого найденного ученика с именем, заканчивающимся на «an»
Вот тут читаем продолжение
- Главная»
- Уроки»
- jQuery»
- Поиск в JSON с помощью DefiantJS
DefiantJS позволяет организовать супер-быстрый поиск в JSON-е, используя XPath выражения, и преобразовать JSON, используя XSL.
Если вам необходимо сделать какой-то поиск в JSON объекте без прокрутки в цикле и дополнительных условий, то вы можете воспользоваться DefiantJS. Данный инструмент позволить осуществить супер-быстрый поиск.
var obj = { "car": [ {"id": 10, "color": "silver", "name": "Volvo"}, {"id": 11, "color": "red", "name": "Saab"}, {"id": 12, "color": "red", "name": "Peugeot"}, {"id": 13, "color": "yellow", "name": "Porsche"} ], "bike": [ {"id": 20, "color": "black", "name": "Cannondale"}, {"id": 21, "color": "red", "name": "Shimano"} ] }, search = JSON.search(obj, '//car[color="yellow"]/name'); console.log( search ); // ["Porsche"] var reds = JSON.search(obj, '//*[color="red"]'); for (var i=0; i<reds.length; i++) { console.log( reds[i].name ); } // Saab // Peugeot // Shimano
Поиск с предварительной подготовкой
В DefiantJS 1.2.0 была введена возможность, с помощью которой скорость поиска можно быть увеличена в 100 раз. Для этого DefiantJS предварительно обрабатывает JSON структуру; это может занять некоторое время. Однако после этого скорость обработки файла размером 1.6MB может быть осуществлена за 4 миллисекунды.
var data { // … крупный JSON файл... }; // Обычный поиск found = JSON.search(data, '//item'); var snapshot = Defiant.getSnapshot(data); // Поиск с предварительной подготовкой found = JSON.search(snapshot, '//item');
5 последних уроков рубрики “jQuery”
-
Анимация набора текста на jQuery
Сегодня мы бы хотели вам рассказать о библиотеке TypeIt — бесплатном jQuery плагине. С её помощью можно имитировать набор текста. Если всё настроить правильно, то можно добиться очень реалистичного эффекта.
-
Временная шкала на jQuery
jQuery плагин для создания временной шкалы.
-
Заметка: Перезагрузка и редирект на JavaScript
Быстрая заметка, где вы сможете найти парочку JS сниппетов для перезагрузки и перенаправления пользователей через JavaScript.
-
Рисуем диаграмму Ганта
jQuery плагин для создания диаграммы Ганта.
-
AJAX и PHP: загрузка файла
Пример того как осуществить загрузку файла через PHP и jQuery ajax.