Vous trouverez ci-dessous un objet JSON que je reçois en réponse. Quelques remarques:
- C'est juste une partie de l'objet
- L'objet n'a pas les mêmes clés pour toutes les sociétés
JSON:
{
"company": {
"result": [
{
"profile": {
"address": "One Microsoft Way",
"bosses": [
{
"name": "Mr. Satya Nadella",
"age": 53,
"totalPay": {
"raw": 13603180,
"fmt": "13.6M",
"longFmt": "13,603,180"
}
},
{
"name": "Mr. Bradford L. Smith",
"age": 61,
"title": "Pres & Chief Legal Officer",
"totalPay": {
"raw": 4265576,
"fmt": "4.27M",
"longFmt": "4,265,576"
}
}
],
"auditRisk": 1,
},
"statistics": {
"enterpriseValue": {
"raw": 1570244395008,
"fmt": "1.57T",
},
"profitMargins": {
"raw": 0.32285
},
"financialCurrency": "USD"
}
}
],
"error": null
}
}
J'aimerais:
- vérifier un certain nombre de chemins dans cet objet
- si le chemin pointe vers une valeur de chaîne, renvoie la valeur si elle existe
- si le chemin pointe vers un tableau, parcourez le tableau pour retourner le chemin de chaque élément du tableau
- si un élément spécifique est nommé dans le chemin, ne renvoie que celui-là
- il doit y avoir une gestion correcte des erreurs
Scénario
var json = JSON.parse(response.getContentText());
var paths = arr[
"profile/address", <-- return the value
"profile/sector", <-- does not exist, return false
"profile/bosses/name", <-- is an array with 2 elements, return both names
"profile/bosses/1/age" <-- only return age of second element
"statistics/enterpriseValue/fmt", <-- return the value
"profitMargins/fmt", <-- does not exist, return false
]
Production attendue:
One Microsoft Way
false
Mr. Satya Nadella
Mr. Bradford L. Smith
53
false
J'ai essayé pendant un certain temps maintenant, mais je suis confus. Peux-tu m'aider?
for (path in paths) {
var steps = path.split('/')
for (step in steps) {
if (step.hasOwnProperty(steps[step+1])) {
if (typeof path[step] === "object") {
// array, so loop again?
}
if (typeof path[step] === undefined) {
// value doesn't exist?
return false;
}
if (typeof path[step] !== undefined) {
return path[step].value;
}
}
}
}
3 réponses
Je pense qu'il y a certaines choses à considérer en premier, donc je ne commence à chercher l'objet que dans le chemin suivant
getPath( data, 'company/result/0' )
Ce qui me permet de commencer beaucoup plus facilement à rechercher les chemins spécifiés.
Je pense que la syntaxe que vous choisissez pour les propriétés n'est peut-être pas la plus simple, car il est un peu plus difficile de décider de rechercher dans tous les éléments ou simplement dans un seul élément du tableau (par exemple, vous recherchez quelque chose comme {{X0 }} d'un élément).
Des sous-tableaux existent toujours dans ce résultat, mais vous pouvez aplatir les résultats si vous le souhaitez.
const data = {
"company": {
"result": [
{
"profile": {
"address": "One Microsoft Way",
"bosses": [
{
"name": "Mr. Satya Nadella",
"age": 53,
"totalPay": {
"raw": 13603180,
"fmt": "13.6M",
"longFmt": "13,603,180"
}
},
{
"name": "Mr. Bradford L. Smith",
"age": 61,
"title": "Pres & Chief Legal Officer",
"totalPay": {
"raw": 4265576,
"fmt": "4.27M",
"longFmt": "4,265,576"
}
}
],
"auditRisk": 1,
},
"statistics": {
"enterpriseValue": {
"raw": 1570244395008,
"fmt": "1.57T",
},
"profitMargins": {
"raw": 0.32285
},
"financialCurrency": "USD"
}
}
],
"error": null
}
};
const pathsToFind = [
"profile/address",
"profile/sector",
"profile/bosses/name",
"profile/bosses/1/age",
"statistics/enterpriseValue/fmt",
"profitMargins/fmt"
];
function getPath( obj, path ) {
if (!path || !obj) {
return null;
}
const [currentPath, ...rest] = path.split('/');
const nextPath = rest.join('/');
const currentObj = obj[currentPath];
// final path, exit here
if (nextPath.length === 0) {
return currentObj;
}
if (Array.isArray( currentObj )) {
// does an element exit at the next level
if ( currentObj[nextPath[0]] ) {
// will continue reading for 1 element
return getPath( currentObj, nextPath );
}
// return all the subpaths, skip the ones that are falsy
return currentObj.map( item => getPath( item, nextPath ) ).filter( v => v );
}
// get the next part of the object
return getPath( currentObj, nextPath );
}
function getMatchingValues( obj, paths ) {
return paths.flatMap( path => getPath( obj, path ) ?? false );
}
console.log( getMatchingValues( getPath( data, 'company/result/0' ), pathsToFind ) );
Il existe plusieurs solutions de contournement pour votre solution, mais je pense que vous pourriez considérer la solution JSONPath comme un moyen standard d'interroger votre objet JSON.
Consultez ce npm JSONPath Guide.
Solution
let data = {
profile: {
address: "One Microsoft Way",
bosses: [
{
name: "Mr. Satya Nadella",
age: 53,
totalPay: {
raw: 13603180,
fmt: "13.6M",
longFmt: "13,603,180",
},
},
{
name: "Mr. Bradford L. Smith",
age: 61,
title: "Pres & Chief Legal Officer",
totalPay: {
raw: 4265576,
fmt: "4.27M",
longFmt: "4,265,576",
},
},
],
auditRisk: 1,
},
statistics: {
enterpriseValue: {
raw: 1570244395008,
fmt: "1.57T",
},
profitMargins: {
raw: 0.32285,
},
financialCurrency: "USD",
},
};
let paths = [
"profile/address",
"profile/sector",
"profile/bosses/name",
"profile/bosses/1/age",
"statistics/enterpriseValue/fmt",
"profitMargins/fmt",
];
let GenratedResult = paths
.map((p) => p.split("/"))
.reduce((allResults, c) => {
let curRes = c.reduce((innerResults, innerCur) => {
if (typeof innerResults === "object" && innerResults.length) {
if (!isNaN(innerCur * 1)) {
return innerResults[innerCur] || false;
} else {
let R = innerResults
.map((v) => v[innerCur] || false)
.filter((i) => i);
return R.length ? R : false;
}
}
return innerResults && innerResults[innerCur]
? innerResults[innerCur]
: false;
}, data);
return [...allResults, curRes];
}, [])
.flatMap((i) => i);
console.log(GenratedResult);
Questions connexes
De nouvelles questions
javascript
Pour des questions concernant la programmation dans ECMAScript (JavaScript / JS) et ses divers dialectes / implémentations (hors ActionScript). Veuillez inclure toutes les balises pertinentes dans votre question; par exemple, [node.js], [jquery], [json], etc.