J'essaie de parcourir le fichier JSON ci-dessous dans PowerShell.
Sans nommer spécifiquement les balises supérieures (par exemple 17443 et 17444), comme je ne les connais pas à l'avance, je ne peux pas trouver un moyen de parcourir les données.
Je veux sortir les tags 3, 4 et 5 (titre, prénom, nom) pour tous les enregistrements.
Comment pourrais-je accomplir cela?
{
"17443":{
"sid":"17443",
"nid":"7728",
"submitted":"1436175407",
"data":{
"3":{
"value":[
"Mr"
]
},
"4":{
"value":[
"Jack"
]
},
"5":{
"value":[
"Cawles"
]
}
},
"17444":{
"sid":"17444",
"nid":"7728",
"submitted":"1436891400",
"data":{
"3":{
"value":[
"Miss"
]
},
"4":{
"value":[
"Charlotte"
]
},
"5":{
"value":[
"Tann"
]
}
}
},
"17445":{
"sid":"17445",
"nid":"7728",
"submitted":"1437142325",
"data":{
"3":{
"value":[
"Mr"
]
},
"4":{
"value":[
"John"
]
},
"5":{
"value":[
"Brokland"
]
}
}
}
}
}
Je peux accéder aux données avec le code ci-dessous, mais je veux éviter de mettre 17443, 17444, etc.
$data = ConvertFrom-Json $json
foreach ($i in $data.17443)
{
foreach ($t in $i.data.3)
{
Write-Host $t.value
}
foreach ($t in $i.data.4)
{
Write-Host $t.value
}
foreach ($t in $i.data.5)
{
Write-Host $t.value
}
}
Dans PowerShell 3.0 et versions supérieures (voir: Déterminer la version PowerShell installée ), vous pouvez utiliser l'applet de commande ConvertFrom-Json
Pour convertir une chaîne JSON en une structure de données PowerShell.
C'est pratique et malheureux à la fois - pratique, car il est très facile de consommer JSON, malheureux parce que ConvertFrom-Json
Vous donne PSCustomObjects , et ils sont difficiles à répéter en tant que paires clé-valeur .
Dans ce JSON particulier, les clés semblent être dynamiques/inconnues à l'avance, comme "17443"
Ou "17444"
. Cela signifie que nous avons besoin de quelque chose qui puisse transformer un PSCustomObject
en une liste de valeurs-clés que foreach
peut comprendre.
# helper to turn PSCustomObject into a list of key/value pairs
function Get-ObjectMembers {
[CmdletBinding()]
Param(
[Parameter(Mandatory=$True, ValueFromPipeline=$True)]
[PSCustomObject]$obj
)
$obj | Get-Member -MemberType NoteProperty | ForEach-Object {
$key = $_.Name
[PSCustomObject]@{Key = $key; Value = $obj."$key"}
}
}
Nous pouvons maintenant parcourir le graphe d'objets et produire une liste d'objets de sortie avec Title
, FirstName
et LastName
$json = '{"17443": {"17444": {"sid": "17444","nid": "7728","submitted": "1436891400","data": {"3": {"value": ["Miss"]},"4": {"value": ["Charlotte"]},"5": {"value": ["Tann"]}}},"17445": {"sid": "17445","nid": "7728","submitted": "1437142325","data": {"3": {"value": ["Mr"]},"4": {"value": ["John"]},"5": {"value": ["Brokland"]}}},"sid": "17443","nid": "7728","submitted": "1436175407","data": {"3": {"value": ["Mr"]},"4": {"value": ["Jack"]},"5": {"value": ["Cawles"]}}}}'
$json | ConvertFrom-Json | Get-ObjectMembers | foreach {
$_.Value | Get-ObjectMembers | where Key -match "^\d+$" | foreach {
[PSCustomObject]@{
Title = $_.value.data."3".value | select -First 1
FirstName = $_.Value.data."4".value | select -First 1
LastName = $_.Value.data."5".value | select -First 1
}
}
}
Sortie
Titre Prénom Nom ----- --------- -------- Mlle Charlotte Tann M. John Brokland
Une approche alternative qui fonctionne également pour PowerShell 2.0 (qui ne prend pas en charge certaines des constructions ci-dessus) impliquerait d'utiliser le .NET classe JavaScriptSerializer pour gérer le JSON:
Add-Type -AssemblyName System.Web.Extensions
$JS = New-Object System.Web.Script.Serialization.JavaScriptSerializer
Maintenant, nous pouvons faire une opération très similaire, même un peu plus simple que ci-dessus, car JavaScriptSerializer vous donne régulièrement Dictionnaires , qui sont faciles à répéter sous forme de paires clé-valeur via la GetEnumerator()
méthode:
$json = '{"17443": {"17444": {"sid": "17444","nid": "7728","submitted": "1436891400","data": {"3": {"value": ["Miss"]},"4": {"value": ["Charlotte"]},"5": {"value": ["Tann"]}}},"17445": {"sid": "17445","nid": "7728","submitted": "1437142325","data": {"3": {"value": ["Mr"]},"4": {"value": ["John"]},"5": {"value": ["Brokland"]}}},"sid": "17443","nid": "7728","submitted": "1436175407","data": {"3": {"value": ["Mr"]},"4": {"value": ["Jack"]},"5": {"value": ["Cawles"]}}}}'
$data = $JS.DeserializeObject($json)
$data.GetEnumerator() | foreach {
$_.Value.GetEnumerator() | where { $_.Key -match "^\d+$" } | foreach {
New-Object PSObject -Property @{
Title = $_.Value.data."3".value | select -First 1
FirstName = $_.Value.data."4".value | select -First 1
LastName = $_.Value.data."5".value | select -First 1
}
}
}
La sortie est la même:
Titre Prénom Nom ----- --------- -------- Mlle Charlotte Tann M. John Brokland
Si votre JSON est supérieur à 4 Mo, définissez la JavaScriptSerializer.MaxJsonLength
Propriété en conséquence.
Si vous lisez un fichier, utilisez Get-Content -Raw -Encoding UTF-8
.
-Raw
Car sinon Get-Content
Renvoie un tableau de lignes individuelles et JavaScriptSerializer.DeserializeObject
Ne peut pas gérer cela. Les versions récentes de Powershell semblent avoir amélioré la conversion de type pour les arguments de la fonction .NET, il est donc possible que cela ne génère pas d'erreur sur votre système, mais si c'est le cas (ou simplement pour être sûr), utilisez -Raw
.-Encoding
Car il est judicieux de spécifier l'encodage d'un fichier texte lorsque vous le lisez et UTF-8
Est la valeur la plus probable pour les fichiers JSON.ConvertFrom-Json()
vous donne un objet personnalisé PowerShell (PSCustomObject
) qui reflète les données dans la chaîne JSON.Get-Member -type NoteProperty
$object."$propName"
, Alternativement $object."$(some PS expression)"
.New-Object PSObject -Property @{...}
, Alternativement [PSCustomObject]@{ .. }
`