在“通配符”位置找到角色

时间:2017-04-11 11:52:31

标签: json powershell

我正在尝试解析一个JSON字符串,该字符串已经从关系数据集中展开,从它的外观...转换为CSV以便导入到Oracle数据库中。我有与此(简化)示例类似的名称/值对

Device.1.Service.1.Channel.1.someProperty : 1,
Device.1.Service.1.Channel.1.someOtherProperty : "billy",
Device.1.Service.1.Channel.2.someProperty : 8,
Device.1.Service.1.Channel.2.someOtherProperty : "frank",
Device.1.Service.1.Channel.3.someProperty : 12,
Device.1.Service.1.Channel.3.someOtherProperty : "sam",
Device.1.Service.2.Channel.1.someProperty : 3,
Device.1.Service.2.Channel.1.someOtherProperty : "john",

编辑:每台设备每天生成一个具有类似结构的.json文件。因此,当合并(Get-Content .\*.json -Raw)时,我看到在控制台中多次出现相同的属性名称。

作为转换的一部分,我希望属性名称的一部分成为数据库中的字段。这将使我们能够使用动态滑块过滤器等更好地可视化数据。

| Device | Service | Channel | someOtherProperty |    
|   1    |   1     |    1    |    billy          | 
|   1    |   1     |    2    |    frank          |
|   1    |   1     |    3    |    sam            |

现在,我正在使用cmdlet ConvertFrom-Json。然后,我使用通配符选择字段(在近2000个可能的字段中)。例如,频道数是动态的。

Get-Content .\*.json -Raw |  ConvertFrom-Json |      
    Select Device.1.Service.1.Channel.?.someOtherProperty

返回PSCustomObject。我想找出频道号并将其用作派生字段。伪示例:

Select @{n="Channel";e={$_.getCharAtWildcard()}},
       $_.theValueofTheCurrentObject()

如果我将所选数据(使用通配符)传输到Get-MemberPSCostomObject包含方法名称和我的字段名称(但不包含值)。

我对如何访问字段名称感到困惑(因为'Name'给出空白行),然后提取通道号(通配符位置的字符),然后正确地构造输出的值。

任何指针?谷歌搜索并有一个lynda.com子,但似乎无法找到这个特定问题的解决方案 - 可能是因为我没有使用正确的条款?

##  ANSGAR's SOLUTION - WORKS FOR SINGLE FILE ##

$dataDir = "C:\ps_json2csv\dummydata"
CD $dataDir

$dict = Get-Content .\*.json -Raw | ConvertFrom-Json | Select -Expand data
$p  = 'DvbId'
$re = "frontend\.(\d+)\.logicalchannel\.(\d+)\.service\.(\d+)\..*?\.$p"

## modified regex to match my data, example string: FrontEnd.2.LogicalChannel.3.Service.1.stat.DvbId 

$fullset = $dict.PSObject.Properties | Where-Object {
    $_.Name -match $re
} | ForEach-Object {
    $prop = [ordered]@{
        FrontEnd       = $matches[1]
        LogicalChannel = $matches[2]
        Service        = $matches[3]
        $p             = $_.Value
    }
    New-Object -Type PSObject -Property $prop
}

## inspect $dict - its populated
## inspect $fullset  - its empty! :(

其中的数据是 C:\ ps_json2csv \ dummydata 中包含的2个文件:

File1.json

{
    "data": {
        "Device.1.Service.1.ChannelInfo.Channel.1.Stats.someProperty" : "1",
        "Device.1.Service.1.ChannelInfo.Channel.2.Stats.someProperty" : "8",
        "Device.1.Service.1.ChannelInfo.Channel.3.Stats.someProperty" : "12",
        "FrontEnd.2.LogicalChannel.3.Service.1.stat.DvbId" : "john",
        "FrontEnd.2.LogicalChannel.3.Service.2.stat.DvbId" : "billy",
        "FrontEnd.2.LogicalChannel.3.Service.3.stat.DvbId" : "frank",
        "FrontEnd.2.LogicalChannel.4.Service.1.stat.DvbId" : "sam",
        "Device.1.Service.2.ChannelInfo.Channel.1.Stats.someProperty" : "3",        
        "Some.value.im.not.intersted.in.just.yet": "Sat Jan 1 00:00:00 GMT 0001",
        "foo.bar" : "0",
        "random.stuff" : "hi there"
    }
}

File2.json

 {
    "data": {
        "Device.1.Service.1.ChannelInfo.Channel.1.Stats.someProperty" : "0",
        "Device.1.Service.1.ChannelInfo.Channel.2.Stats.someProperty" : "7",
        "Device.1.Service.1.ChannelInfo.Channel.3.Stats.someProperty" : "6",
        "FrontEnd.2.LogicalChannel.3.Service.1.stat.DvbId" : "john",
        "FrontEnd.2.LogicalChannel.3.Service.2.stat.DvbId" : "billy",
        "FrontEnd.2.LogicalChannel.3.Service.3.stat.DvbId" : "frank",
        "FrontEnd.2.LogicalChannel.4.Service.1.stat.DvbId" : "sam",
        "Device.1.Service.2.ChannelInfo.Channel.1.Stats.someProperty" : "4",        
        "Some.value.im.not.intersted.in.just.yet": "Sun Jan 2 00:00:00 GMT 0001",
        "foo.bar" : "0",
        "random.stuff" : "hi there"
    }
}

2 个答案:

答案 0 :(得分:0)

我宁愿将此语法的字符串转换为具有整套属性的PSObject。像这样:

$dict=Get-Content .\*.json -Raw |  ConvertFrom-Json
$fullset=$dict.psobject.properties | % {
    $parse=$_.name.split('.')
    $parse+=,$_.value # since JSON values might be non-plain, we need to add the value as single object
    $obj=new-object psobject
    for ($i=0;$i -lt $parse.length;$i+=2) { # name-value
        $v1=$parse[$i]
        $v2=$parse[1+$i]
        $obj | add-member -type noteproperty -name $v1 -value $v2
    }
    $obj
 }

然后你就像使用$fullset等普通列表一样解析where {$_.device -eq '1' -and $_.someOtherProperty -ne $null}

答案 1 :(得分:0)

我可能会使用正则表达式匹配来过滤和提取数据:

$p  = 'someOtherProperty'
$re = "device\.(\d+)\.service\.(\d+)\..*?\.channel\.(\d+)\..*?\.$p"

$fullset = $dict.PSObject.Properties | Where-Object {
    $_.Name -match $re
} | ForEach-Object {
    $prop = [ordered]@{
        Device  = $matches[1]
        Service = $matches[2]
        Channel = $matches[3]
        $p      = $_.Value
    }
    New-Object -Type PSObject -Property $prop
}