【问题标题】:Looping through API XML data is not being added to the array correctly循环 API XML 数据未正确添加到数组中
【发布时间】:2019-03-18 17:01:15
【问题描述】:

这里是 XML。我正在寻找siteid。

<result created="2018-10-13T13:11:18-05:00" host="redacted" status="OK">
<items>
<site>
<siteid>399700</siteid>
<name>
<![CDATA[ Warehouse ]]>
</name>
<connection_ok>1</connection_ok>
</site>
<site>
<siteid>547401</siteid>
<name>
<![CDATA[ Monterey Park ]]>
</name>
<connection_ok>1</connection_ok>
</site>
</items>
</result>

要获取我要查找的数据,我首先需要遍历 XML 以获得客户端 ID,然后我可以使用客户端 ID 来查找每个客户端的站点 ID。一些客户有多个站点。

虽然正确获得了客户,但由于缺乏更好的术语,网站被压缩了。

结果:

客户编号:12345 站点编号:9876543210

站点 ID 应该是两个单独的数字:98765 43210

这是我正在使用的两个函数:

$ClientsIDs = @()
$SiteIDs = @()

function Get-Clients() {
    $clientdata = Invoke-RestMethod -Uri ($baseurl + $lc)
    $clientid = $clientdata.result.items.client.clientid
    $Script:ClientsIDs += $clientid
    Write-Output("Client ID: " + $ClientsIDs)
}

function Get-Sites() {
    foreach ($id in $Global:ClientsIDs) {
        $sitedata = Invoke-RestMethod -Uri ($baseurl + $ls + $id)
        $siteid = $sitedata.result.items.site.siteid 
        $SiteIDs += $siteid
    }
    Write-Output("Site ID: " + $SiteIDs)
}

Get-Clients
Get-Sites

(只有 URL 没有显示。Write-Outputs 只是为了我的利益,以确保正确收集数据。它们最终将被删除。)

如何让$sitedid 正确保存在数组中?

【问题讨论】:

    标签: arrays xml powershell


    【解决方案1】:

    tl;dr

    我建议重构你的代码,这样可以避免你的问题,而且效率更高,封装性更好:

    function Get-Sites() {
        # Note: Also consider passing the parent-scope 
        #       $ClientsIDs, $baseurl, $ls variables as *parameters* instead.
        foreach ($id in $ClientsIDs){
            $sitedata = Invoke-RestMethod -Uri ($baseurl + $ls + $id)
            # Implicitly output each site ID, which by
            # virtue of being inside a foreach loop outputs
            # all of them as an array.
            $sitedata.result.items.site.siteid 
        }
    }
    
    # If you wanted to interpret the IDs as *numbers*, you
    # could use type [int[]], for instance
    [array] $SiteIDs = Get-Sites
    

    至于你尝试了什么

    分配给 $SiteIDs 没有范围修饰符 script ($script:SiteIDs),你错误地创建了一个本地 em> $SiteIDs 变量在您的 Get-Sites 函数中。

    鉴于范围看到 - 但不能直接分配给 - 来自范围的变量,本地复制由赋值创建的$SiteIDs 从父作用域继承同名变量的类型(和值)(请参阅this answer 以了解有关PowerShell 中作用域的更多信息)。

    如果$SiteIDs 确实是您脚本范围内的一个数组,那么您的本地副本也会创建一个 array - 但这仍然不会修改 original 数组脚本范围。

    在您的情况下,$SiteIDs 最终包含您的站点 ID 的 字符串连接,这表明您的 实际 代码也没有 在脚本范围内创建一个 $SiteIDs 变量,或者它是 string 类型的,而不是 array (@()),因为将带有字符串的+= 与作为RHS 的字符串应用到[string] 类型或以前不存在的变量执行简单的字符串连接(将RHS 直接附加到现有值,默认为空字符串,如果变量不存在)。

    立即修复将是:

    • 确保$SiteIDs = @() 真正定义在脚本范围内,即作为一个数组

    • $SiteIDs += $siteid更改为$script:SiteIDs += $siteid,以便按预期直接修改脚本范围变量。

    也就是说,通常最好避免跨范围边界引用变量 - 使用参数和局部变量来更好地封装,如顶部所示。

    【讨论】:

    • 很高兴听到这个消息,@MBH;我的荣幸。
    【解决方案2】:
    [array]$SiteIDs += $siteid
    
    # or
    
    function Get-Sites() {
        $SiteIDs=@()
        foreach ($id in $Global:ClientsIDs){
            ...
            $SiteIDs += $siteid
    
    # or; for better performance
    
    function Get-Sites() {
        $SiteIDs=New-Object System.Collections.ArrayList
        foreach ($id in $Global:ClientsIDs){
            ...
            $SiteIDs.add($siteid)
    

    【讨论】:

    • 为了获得最佳性能:[array] $SiteIDs = foreach { ... }(或$SiteIDs = @(foreach { ... }))。也就是说,OP 的主要问题是无意中创建了 local $SiteIDs 变量,而他们的意图是直接修改 parent 范围的变量,因为缺少输出来自函数(如上所述,Write-Output 调用仅用于调试)。
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2013-07-25
    • 2019-04-03
    • 2019-03-28
    相关资源
    最近更新 更多