【问题标题】:finding the character at 'wildcard' position在“通配符”位置找到字符
【发布时间】:2017-09-06 19:03:42
【问题描述】:

我正在尝试解析一个 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) 时,我会在控制台中看到相同的属性名称多次出现。

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

|设备 |服务 |频道 |一些其他属性 | | 1 | 1 | 1 |比利 | | 1 | 1 | 2 |坦率 | | 1 | 1 | 3 |山姆 |

现在,我正在使用 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 包含方法名称以及我的字段名称(但不包含值)。

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

有什么建议吗?谷歌搜索并有一个 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 个文件:

文件1.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"
    }
}

文件2.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"
    }
}

【问题讨论】:

    标签: json powershell


    【解决方案1】:

    我宁愿将此语法的字符串转换为带有您的整个属性集的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} 等的普通列表一样。

    【讨论】:

    • 我想在说之前完全理解脚本块在做什么 - 我看不出这将如何让我解析动态数量的频道、服务或设备。我想向分析师提供所有数据。它必须在数据库中才能链接到可视化软件。我不需要查询吗? $_.Channel -eq 99(如果存在)以及该通道之前的所有内容并使用带有硬编码标签的 Select-object ?
    • 我正在尝试学习 powershell,所以会缺少一些基本概念。但是该脚本会引发错误,因为它试图创建一个已经存在的名称。它创建的名称(并试图覆盖)看起来像一个数组/对象...即添加成员:无法添加名称为“@{someName=someValue; someOtherName=somOtherValue; somethingElse=aValue ... .. 等] }"
    • 啊,明白了。当 JSON 中的值是数组/对象(嵌套对象)时,$parse+=$_.value 会展平数组,而我不需要它来执行此操作。它应该保持一个元素。明天再更新,因为我现在没时间。
    • 好的,您的示例适用于样本和简化数据集。我看到 $fullset 在控制台中采用表格格式,我认为这对我有用 - 非常感谢。要与我的实际数据集成 - 我需要了解脚本。
    • 1. dict.psobject.properties 是如何工作的?当我在 psobject 上执行 get-member 时,值的名称包含在名为 SyncRoot 的属性中... 2. 您将道具名称字符串拆分为“。”并放入一个数组($ parse)?这是名称的individual 段?数组长度是 7 吗?然后将道具值推到数组的末尾?我如何检查 $_.name 和 $_.value... 以及此时 $parse... 3. 创建一个新的 psobject 并遍历 $parse 数组(为什么要执行 2 步?)
    【解决方案2】:

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

    $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
    }
    

    【讨论】:

    • 这很好而且非常有用,但是我发现数据文件中的 if 属性名称是相同的,只有最后一个出现在输出中。展示。使用如下数据...(其中通道 1 重复,只有其中一个进入输出)
    • “Device.1.Service.1.ChannelInfo.Channel.1.Stats.someProperty”:“1”,“Device.1.Service.1.ChannelInfo.Channel.1.Stats.someOtherProperty “:“比利”,“Device.1.Service.1.ChannelInfo.Channel.2.Stats.someProperty”:“8”,“Device.1.Service.1.ChannelInfo.Channel.2.Stats.someOtherProperty”: “坦率”,“Device.1.Service.1.ChannelInfo.Channel.3.Stats.someProperty”:12,“Device.1.Service.1.ChannelInfo.Channel.1.Stats.someOtherProperty”:“sam”
    • @lee_dabiker 这就是 JSON 的工作原理。 JSON 是对象数据的文本表示。对象不能有两个同名的属性。
    • 每天捕获数据。每天一个新文件,重复所有参数。文件中的一个参数是用户 ID,另一个是时间戳。在 Powershell 中转换为 JSON 后,select-object(带有通配符)仍然设法维护每天的所有重复属性。
    • JSON 和 ConvertFrom-Json 不能那样工作。如果您的实际数据看起来像您的示例数据,那么您将仅从重复属性中获得最后一个值。否则,请提供与您的真实数据非常相似的样本。
    猜你喜欢
    • 2015-08-05
    • 1970-01-01
    • 2021-04-04
    • 1970-01-01
    • 2011-05-21
    • 1970-01-01
    • 1970-01-01
    • 2012-04-28
    • 2021-05-24
    相关资源
    最近更新 更多