【问题标题】:Powershell - Parsing inconsistent Json DataPowershell - 解析不一致的 Json 数据
【发布时间】:2019-04-07 14:01:57
【问题描述】:

我得到了一个包含 ID 和 Json 数据的 CSV 文件。我需要将数据解析为 CustomerData 类。

但是,我在访问给定键的值时遇到问题

我得到了这个 CSV 文件。 Json 可能在某些记录中包含一些键,而在其他记录中可能不存在。基本上只存在已更新的字段。

ID;CHANGES
713422;[{"key":"zipCode","updatedValue":""},,{"key":"language","updatedValue":"EN"},{"key":"coaddress","updatedValue":""},{"key":"SSN","updatedValue":""},{"key":"msisdn","updatedValue":"1114455789"}]
114365;[{"key":"city","previousValue":"New York","updatedValue":"Palm City"},{"key":"zipcode","previousValue":"100012","updatedValue":"02118"},{"key":"coaddress","updatedValue":""},{"key":"streetaddress","previousValue":"9253 Del Monte Road"updatedValue":"90 Kent Ave"},{"key":"SSN","updatedValue":""},{"key":"companyName","previousValue":"Nutrics","updatedValue":"NutriTiger"}]
114365;[{"key":"zipCode","updatedValue":""},{"key":"coaddress","updatedValue":""},{"key":"SSN","updatedValue":""},{"key":"companyName","previousValue":"NutriTiger","updatedValue":"Nutri-Tiger"}]
713422;[{"key":"zipCode","updatedValue":""},{"key":"coaddress","updatedValue":"Roady Road"},{"key":"SSN","updatedValue":""},{"key":"msisdn","updatedValue":""}]

我想做的是这样的。 Json 数据中可能出现 8 个键,我需要检查它是否存在,如果存在则获取值。

$city
if (TryParse(Json.city.GetValue, $city )
{
    CustomerData.$city = Json.city.GetValue
}

这就是我现在的样子。我被困在 If 语句中,我尝试以不同的方式访问 $jsondata。 我试过了 $jsonData.city $jSonData.getValue('city') 不同类型的管道 $jsonData 并做选择

但我似乎无法获得给定键的值。

我最终需要的是构建一个新的 CSV 文件,在其中搜索 ID,然后更新给定字段,例如城市(如果已更新)。

class CustomerData
{
    [int]$Id = 0

    [string]$companyName = ""
    [string]$ssn = ""
    [string]$msisdn = ""
    [string]$language = ""

    [string]$city = ""
    [string]$coaddress = ""
    [string]$streetaddress = ""
    [string]$zipCode = ""
}

$inputdata = ".\Testdata.csv"

$iso8859_1 = [System.Text.Encoding]::GetEncoding('ISO-8859-1')

    $reader = New-Object -TypeName System.IO.StreamReader($inputdata, $iso8859_1)
    [int]$counter = 0

    while ($line = $reader.ReadLine() )
    {   

        if ($counter -gt 0)
        {
            $lines_split = $line.Split(';')
            CustomerData.$Id = $lines[0]
            $jsondata = ConvertFrom-Json $lines[1] 
        }
        $counter++;
    }
    $reader.Close()

【问题讨论】:

  • 看起来像是 jmespath 的工作 - 你试过使用它吗?
  • 感谢您的提示!我不能为此使用它,但我一定会检查一下。工具箱里的东西看起来很不错。

标签: json powershell parsing


【解决方案1】:

尝试从以下 sn-p 中获得一些想法:

$reader = [System.IO.StringReader]::new(@'
ID;CHANGES
713422;[{"key":"zipCode","updatedValue":";"},{"key":"language","updatedValue":"EN"},{"key":"coaddress","updatedValue":""},{"key":"SSN","updatedValue":""},{"key":"msisdn","updatedValue":"1114455789"}]
114365;[{"key":"city","previousValue":"New York","updatedValue":"Palm City"},{"key":"zipcode","previousValue":"100012","updatedValue":"02118"},{"key":"coaddress","updatedValue":""},{"key":"streetaddress","previousValue":"9253 Del Monte Road","updatedValue":"90 Kent Ave"},{"key":"SSN","updatedValue":""},{"key":"companyName","previousValue":"Nutrics","updatedValue":"NutriTiger"}]
114365;[{"key":"zipCode","updatedValue":""},{"key":"coaddress","updatedValue":""},{"key":"SSN","updatedValue":""},{"key":"companyName","previousValue":"NutriTiger","updatedValue":"Nutri-Tiger"}]
713422;[{"key":"zipCode","updatedValue":""},{"key":"coaddress","updatedValue":"Roady Road"},{"key":"SSN","updatedValue":""},{"key":"msisdn","updatedValue":""}]
'@)
class CustomerData
{
  [int]$Id = 0

  [string]$companyName = ""
  [string]$ssn = ""
  [string]$msisdn = ""
  [string]$language = ""

  [string]$city = ""
  [string]$coaddress = ""
  [string]$streetaddress = ""
  [string]$zipCode = ""
}
$props = [CustomerData].GetProperties() | ForEach-Object Name
$counter = 0
while ( $line = $reader.ReadLine() )
{
  if( $counter -gt 0 )
  {
    $cd = [CustomerData]::new()
    $cd.Id, $ch = $line.Split(';')
    $ch = $ch -join ';'
    $jsondata = ConvertFrom-Json $ch
    $jsondata | Where-Object { $props -contains $_.key } |
      ForEach-Object { $cd."$($_.key)" = $_.updatedValue }
    $cd
  }
  $counter++
}
$reader.Close()

【讨论】:

  • 这行得通!我一直在玩它一点点,它正是我想要的。如果我的想法解决这个问题是一个好的解决方案,那就是另一回事了,虽然呵呵。我不太了解 If 语句中倒数第二行的所有内容(Where-object {$props -contains $_.key} 等)。我理解代码,但我现在无法复制它或稍后在不同的情况下使用它。需要谷歌并阅读。 :) 谢谢!
【解决方案2】:

Andrei Odegov's answer 包含对您的代码有用的改进。
正如目前所发布的,您的代码的主要问题是变量名混淆:您将字段保存到数组$lines_split,然后错误地访问了一个不同变量$lines

一般来说,至少默认情况下不需要类似于TryParse():您可以简单地访问属性路径,如果它不存在,$null 将被退回:

$bar = ('{ "foo": 1 }' | ConvertFrom-Json).bar  # $bar will be $null

如果Set-StrictMode -Version 2 或更高版本有效,访问不存在的属性会导致(语句终止)错误;使用try / catch 是处理此问题的最简单方法,它还允许您指定一个默认值

$bar = try { ('{ "foo": 1 }' | ConvertFrom-Json).bar } catch { 0 }  # $bar will be 0

也就是说,您的特定 JSON 输入的结构方式是目标属性 names 在 JSON 属性 values 中,这会阻止直接访问,例如 $obj.City,所以你需要过滤对象。

但是,与其寻找特定的值,不如考虑对它们进行迭代

# Instantiate a new customer-data object.
$customer = [CustomerData]::new()

# Parse the JSON data in custom objects ([pscustomobject]).
# In this case, you'll get a single-element array containing an array
# of [pscustomobject] instances.
$jsondata = ConvertFrom-Json '[{"key":"city","previousValue":"New York","updatedValue":"Palm City"},{"key":"zipcode","previousValue":"100012","updatedValue":"02118"},{"key":"coaddress","updatedValue":""},{"key":"streetaddress","previousValue":"9253 Del Monte Road","updatedValue":"90 Kent Ave"},{"key":"SSN","updatedValue":""},{"key":"companyName","previousValue":"Nutrics","updatedValue":"NutriTiger"}]'


# Loop over all custom objects and update the corresponding
# customer-data properties.
foreach($obj in $jsonData) {
   $propName = $obj.key
   $customer.$propName = $obj.UpdatedValue
}

【讨论】:

  • 不用担心,@SuperKyllingen。很高兴听到常见问题解答很有帮助。享受实验。
猜你喜欢
  • 1970-01-01
  • 2013-02-25
  • 1970-01-01
  • 2019-04-17
  • 2013-10-13
  • 2017-10-23
  • 2015-11-26
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多