Looping and searching through JSON using PowerShell - json

I have a JSON file that has following contents:
{
"status": "UP",
"details": {
"graphDBCheck": {
"status": "UP"
},
"ds": {
"status": "UP",
"details": {
"total": 100,
"free": 50,
"threshold": 30
}
},
"db": {
"status": "UP",
"details": {
"ADS": {
"status": "UP",
"details": {
"database": "Influx",
"hello": "Hello"
}
},
"EARDS": {
"status": "UP",
"details": {
"database": "Oracle",
"hello": "Hello"
}
},
"EFRDS": {
"status": "UP",
"details": {
"database": "Sybase",
"hello": "Hello"
}
}
}
}
}
}
I need to be able to transform this into a CSV file that has each element's name as header and it's status or value as the next row. First "status" would have column name "API_Status"
For instance:
API_Status,graphDBCheck,ds,db,ADS,EARDS,EFRDS
UP,UP,UP,UP,UP,UP,UP
Challenge here is to make this dynamic so the output will always include any other element added that has "status" in it.
I tried this and it works but I need a dynamic way do to this:
$x = Invoke-RestMethod $url -Verbose:$VerbosePreference
[pscustomobject][ordered]#{
'API_Status' = $x.status
'db' = $x.details.db.status
'ds' = $x.details.diskspace.status
'ds_Total' = $x.details.ds.details.total
'ds_Free' = $x.details.ds.details.free
'graphDBCheck' = $x.details.graphDBCheck.status
'ADS' = $x.details.db.details.auroraDataSource.status
'EARDS' = $x.details.db.details.EARDS.status
'EFRDS' = $x.details.db.details.edsFirstRowsDataSource.status
}

In an ideal world, the json would be structured like this, as an expandable array with uniform properties.
[
{
"name": "API_Status",
"status": "UP"
},
{
"name": "graphDBCheck",
"status": "UP"
},
{
"name": "ds",
"status": "UP"
},
{
"name": "db",
"status": "UP"
},
{
"name": "ADS",
"status": "UP"
},
{
"name": "EARDS",
"status": "UP"
},
{
"name": "EFRDS",
"status": "UP"
}
]
Or as a csv:
name,status
API_Status,UP
graphDBCheck,UP
ds,UP
db,UP
ADS,UP
EARDS,UP
EFRDS,UP
There's plenty of other posts about looping through powershell properties Iterate over PSObject properties in PowerShell or looping through json properties: Iterating through a JSON file PowerShell

Related

Is there a better way for me to loop through json nodes in PowerShell

I am wondering if someone could help me and make a suggestion.
I have a JSON file as seen below that contains a few different nodes, I have removed the values for confidentiality purposes. I need to be able to loop through each test step as provided by the JSON and pull the tests that have a step with a status of failed.
So far the easiest way I have found of doing this is nesting for each loop's (Report-> Description-> Element-> Step-> Result-> Status) I am wondering if there are any PowerShell Gurus that can assist me in finding a possible cleaner and faster solution for this?
[
{
"description": "",
"elements": [
{
"description": "",
"id": "",
"keyword": "Scenario",
"line": 9,
"name": "",
"tags": [
{
"name": "",
"line": 1
},
{
"name": "",
"line": 1
},
{
"name": "",
"line": 1
}
],
"steps": [
{
"keyword": "Given ",
"line": 0,
"match": {
"location": ""
},
"name": "",
"result": {
"duration": 41560.8294,
"error_message": null,
"status": "Failed"
}
}
],
"name": "",
"uri": ""
},
{
"description": "",
"elements": [
{
"description": "",
"id": "",
"keyword": "Scenario",
"line": 14,
"name": "",
"tags": [
{
"name": "",
"line": 1
},
{
"name": "",
"line": 1
},
{
"name": "",
"line": 1
},
{
"name": "",
"line": 1
},
{
"name": "",
"line": 1
}
],
"steps": [
{
"keyword": "Given ",
"line": 0,
"match": {
"location": ""
},
"name": "",
"result": {
"duration": 17133.4242,
"error_message": ,
"status": ""
}
}
],
"name": "",
"uri": ""
}
]
[String]$report = Get-Content $inputPath
[System.Object[]]$json = ConvertFrom-Json -InputObject "$report"
[String[]]$failedTests = #()
foreach($feature in $json)
{
foreach($scenario in $feature.elements)
{
foreach($step in $scenario.steps)
{
if(($scenario.steps).Where({ $step.result.status -eq "Failed" }, 'First').Count -gt 0)
{
$failedTests += Generate-FullyQualifiedName $ProjectName $feature.name $scenario.name
break
}
}
}
}
What you've got is pretty much the best way to return multiple "depths" of an object in powershell, since there's not really a .
One improvement is to force powershell to use a [list[]] type object instead of the default fixed-length [System.Array] created by $foo = #(), which has to be destroyed and recreated every time it's extended with +=. Instead, try using:
$failedTests = [System.Collections.Generic.List[String]]::new()
# loops...
$failedTests.Add((Generate-FullyQualifiedName -etc))
You also don't need to loop through each step either to check if a scenario failed:
foreach($scenario in $feature.elements) {
# -- Skip foreach $step
if($scenario.steps.result.status -eq 'Failed') {
$failedTests.Add((Generate-FullyQualifiedName -etc))
}
}
For most purposes, I would stick with the looping you're doing. Depending on how huge each object actually is, it can be a little faster (and uglier) to iterate on an array index int instead of assigning the whole $feature object to a variable, but I doubt it would help much here.

Cannot get array property by using Parse JSON groovy

I'm new to Groovy. But, I can try with some simple code lines to extract the data.
I have read the from Parse JSON using groovy script (using JsonSlurper). But it didn't help in my case.
My code line:
{
"errors": false,
"address_data": [
{
"address_id": "567",
"township": {
"id": "41079",
"name": "Test Data"
},
"city": {
"id": "1622",
"name": "Test City"
},
"region": {
"id": "663",
"name": "Metro Test"
},
"stock_source_code": "Test",
"is_default_address": false
},
{
"address_id": "45444",
"township": {
"id": "41079",
"name": "Test Test"
},
"city": {
"id": "1622",
"name": "Test City"
},
"region": {
"id": "663",
"name": "Metro Test Taguig"
},
"is_default_address": true
},
{
"address_id": "45444",
"township": {
"id": "888888",
"name": "Apas"
},
"city": {
"id": "432",
"name": "Test City"
},
"region": {
"id": "591",
"name": "Test Cebu"
},
"stock_source_code": "testce",
"is_default_address": false
}
]
}
My code lines:
def response = "data_above";
def object = new JsonSlurper().parseText(response);
def errors = object.errors
if (errors == false) { //could access object.errors property
log.info "Checking condition"
def addressData = object.address_data // Cannot get the data
}
How can I get the address_data property?

Add the same element of array in a existing JSON using jq

I have a json file and I want to add some value from top in another place in json.
I am trying to use jq command line.
{
"channel": "mychannel",
"videos": [
{
"id": "10",
"url": "youtube.com"
},
{
"id": "20",
"url": "youtube.com"
}
]
}
The output would be:
{
"channel": "mychannel",
"videos": [
{
"channel": "mychannel",
"id": "10",
"url": "youtube.com"
},
{
"channel": "mychannel",
"id": "20",
"url": "youtube.com"
}
]
}
in my json the "channel" is static, same value always. I need a way to concatenate always in each video array.
Someone can help me?
jq .videos + channel
Use a variable to remember .channel in the later stages of the pipeline.
$ jq '.channel as $ch | .videos[].channel = $ch' tmp.json
{
"channel": "mychannel",
"videos": [
{
"id": "10",
"url": "youtube.com",
"channel": "mychannel"
},
{
"id": "20",
"url": "youtube.com",
"channel": "mychannel"
}
]
}

How to parse this JSON in PHP

I build this JSON from my form generated on my website.
I now want to push the individual item's to the database, so I need to be able to pull out instruction by iteration.
$instruction0
$instruction1
and the ingredients which sit inside an instruction.
When trying to parse the JSON I get an error, I am not sure how to read it in PHP. (AKA PHP NOOB) I am able to get all my item's needed via Python without any issues.
Error
[
[
{
"instruction": "Enter text here...asdada"
},
{
"ingredient": "Beetroot",
"amount": "2",
"type": "grams"
},
{
"ingredient": "Beetroot",
"amount": "1",
"type": "grams"
}
],
[
{
"instruction": "Enter text here..sdfsdf."
},
{
"ingredient": "Carrot",
"amount": "2",
"type": "grams"
},
{
"ingredient": "Beetroot",
"amount": "525",
"type": "grams"
}
]
]
Have you tried json_decode with a second parameter 'true' to specify you want your output as an associative array.
json_decode($json, true);
Secondly, if you are posting this json string manually into your code, you need to wrap it inside quotes, so based on that
$json = '[ [ { "instruction": "Enter text here...asdada" }, { "ingredient": "Beetroot", "amount": "2", "type": "grams" }, { "ingredient": "Beetroot", "amount": "1", "type": "grams" } ], [ { "instruction": "Enter text here..sdfsdf." }, { "ingredient": "Carrot", "amount": "2", "type": "grams" }, { "ingredient": "Beetroot", "amount": "525", "type": "grams" } ] ] ';
$array = json_decode($json, true);
Then you can iterate through $array as normal

Linq to Json using Like Clause

I've got an MVC 3 web app and am returning a JSON object which I would like to use Linq against to limit the result returned to the client jquery.
The Json response takes the following structure:
{
"Data": {
"Items": [
{
"Result": {
"Id": "e2ba4912-c387-4f54-b55e-06742a6858db",
"Name": "SomeOtherSetting",
"Value": "500",
"Archived": false
},
"Result": {
"Id": "17c27584-cea8-42c2-b6c4-0b30625ac3ce",
"Name": "Setting2",
"Value": "600",
"Archived": false
},
"Result": {
"Id": "17c27584-cea8-42c2-b6c4-0b30625ac3ce",
"Name": "Setting3",
"Value": "700",
"Archived": false
}
}]
}
}
....
I need to return or grab just the json items that have a Name like 'Setting' for example. In the example, this would return just the 2 Json nodes.
My Linq is very limited and what I have is: Settings is where the Json response is stored.
NewtonSoft.Json.Linq.JObject data = NewtonSoft.Json.Linq.JObject.Parse(Settings);
var result = from p in data["Data"]["Items"].Children()
where (p["Result"]["Name"].Contains("Expenses.Help.Tip"))
select new { Name = (string)p["Result"]["Name"], Value = (string)p["Result"]["Value"] };
When I run this I get nothing in my result. Can anyone help and tell me what I'm doing wrong?
Thanks.
Well, I'm not a Json specialist, but I think your Json structure has some problems.
I tried an online parser, and parsing took only the third result... (try to copy past your code in the left window, and look at JS eval.
Instead of
"Items": [
{
"Result": {
},
"Result": {
},
"Result": {
}
}]
you should have each element of Items array (each 'Result') into {}.
"Items": [
{
{"Result": {
}
},
{"Result": {
}
},
{"Result": {
}
}]
I got it to work by changing your Json file to
{
"Data": {
"Items": [
{
"Result": {
"Id": "e2ba4912-c387-4f54-b55e-06742a6858db",
"Name": "SomeOtherSetting",
"Value": "500",
"Archived": false
}
},
{
"Result": {
"Id": "17c27584-cea8-42c2-b6c4-0b30625ac3ce",
"Name": "Setting2",
"Value": "600",
"Archived": false
}
},
{
"Result": {
"Id": "17c27584-cea8-42c2-b6c4-0b30625ac3ce",
"Name": "Setting3",
"Value": "700",
"Archived": false
}
}]
}
}
using
var data = JObject.Parse(test)["Data"]["Items"].Children()
.Where(m => m["Result"]["Name"].Value<string>().Contains("Setting"))
.Select(m => new
{
Name = m["Result"]["Name"].Value<string>(),
Value = m["Result"]["Value"].Value<int>()
})
.ToList();