来自xml

时间:2015-12-14 02:33:13

标签: xml powershell

我在这里画一个空白,我确信答案就在我面前。我正在尝试构建一个动态菜单,以便在WinPE映像中启动小型应用程序。我正在使用XML文件来获取数据(这似乎是最合适的)

现在我的xml文件看起来像这样

<Programs>
    <!-- Programs -->
    <Program Name="7-Zip" Path="\7-Zip\7zFM.exe" Type="Addin"/>
    <Program Name="HwMonitor" Path="\HwMonitor\HwMonitor.exe" Type="Addin"/>
    <!-- HDTools -->
    <Program Name="Defraggler" Path="\Defraggler64\Defraggler64.exe" Type="Hdtools"/>
</Programs>

我遇到了问题,我写的函数是采用$Type参数,所以我可以根据类型进行过滤。过滤器本身工作正常,它是下面用于构建菜单的部分....只有当多个项目符合该条件时才有效。

Function Select-Program($Type)
{
    clear; MenuHeader
    Write-Host " ----------------------------------------------------------------------- "

    $List = $null # set the list to null, for some reason there was duplication when re-entering the menu

    try
    {
        $AddinPath = switch([System.IntPtr]::Size)
        {
            8 {Join-Path (Get-PEDrive).DriveLetter "Programs64"}
            4 {Join-Path (Get-PEDrive).DriveLetter "Programs"}
        }

        $ListFile = Join-Path $AddinPath "Programs.xml"

        [xml]$Programs = Get-Content $ListFile
        Write-Host " "
        $List = $Programs.DocumentElement.Program | Where-Object {$_.Type -eq $Type}

    }
    catch [exception]
    {
    $_.Exception
    }

    # if there's no items in the list, then write a message
    if ($List.Count -eq 0)
    {
        Write-Host "  No Programs Found" -ForegroundColor Red
        Write-Host " "
    }

    $menu = @{}

    # build menu item list dynamically from the imported data

    for ($i=1;$i -le $List.count; $i++) 
    {
        Write-Host "  $i. $($List[$i-1].Name)" -foregroundcolor White
        $menu.Add($i,($List[$i-1].Name))
    }

    # add one last item to return to main menu
    Write-Host "  $i. Return to main menu" -foregroundcolor White
    $menu.Add($i,"return")

    #prompt for selection
    Write-Host " "
    [int]$ans = Read-Host ' Enter selection'
    $selection = $menu.Item($ans)

    if ($selection -eq "return")
    {
        MainMenu
    }

    # launch the selected application
    $Launch = Join-Path $AddinPath ($List | Where-Object {$_.Name -eq $selection}).Path
    Start-Process $Launch

    Select-Program -Type $Type # reload the program menu
}

如果我使用上面的XML运行“Select-Program -Type Addin”,我会得到一个包含2个项目的菜单,以及返回主菜单。但是,如果我运行“Select-Program -Type Hdtools”,我什么也得不到,因为XML文件中只有一个具有此类型的项目。

今天早上我尝试使用CSV文件,我得到同样的东西,所以我不认为它与数据的来源或我从哪种格式中提取它有任何关系。

我在这里缺少什么?我不敢操作员弄乱了我,所以我尝试了不到或者相等,但是我也遭到了轰炸,让我现在挠挠脑袋

2 个答案:

答案 0 :(得分:1)

我打算提出一种不同的方法,我认为这会简化整个过程。

首先,生成表示您在XML中存储的内容的对象,然后将它们导出为CliXML或JSON:

$objects = @()
$objects += [PSCustomObject]@{
    Name = "7-Zip"
    Path = "\7-Zip\7zFM.exe"
    Type = "Addin"
}
$objects += [PSCustomObject]@{
    Name = "Defraggler"
    Path ="\Defraggler64\Defraggler64.exe"
    Type = "Hdtools"
}
# etc.
$objects | Export-CliXml -Path C:\my.xml
$objects | ConvertTo-Json | Set-Content -Path C:\my.json

现在,当你想把它们带回来时:

# from xml
$List = Import-CliXml -Path C:\my.xml

# or from JSON
$List = Get-Content -Path C:\my.json -Raw | ConvertFrom-Json

$List = $List | Where-Object { $_.Type -eq $Type } 

$menu = @{}
for ($i=1;$i -le $List.count; $i++)
{
    Write-Host "  $i. $($List[$i-1].Name)" -foregroundcolor White
    $menu.Add($i,($List[$i-1].Name))
}

我认为这简化了以一致方式导出和导入对象的过程。该数组应该作为导出过程的一部分进行序列化,并作为导入的一部分进行反序列化,因此您不必担心返回单个对象的方法或cmdlet。

答案 1 :(得分:0)

我解决了。问题是,当只有一个项目时,PowerShell会以不同的方式处理数组。我遇到了从CSV导入的相同行为。这似乎特别是通过Where-Object cmdlet管道数据

当只有一个项目从通过Where-Object传送的XML $ List变量中提取时,$ List [0] .Name返回一个空字符串,其中$ List.Name返回所需的值。

解决方案是改变这个

$menu = @{}
for ($i=1;$i -le $List.Name.count; $i++) 
{
    $DisplayName = switch([string]::IsNullOrEmpty($List[$i-1].Name))
    {
        $true {$List.Name}
        $false {$List[$i-1].Name}
    }

    Write-Host ([string]::Format("  {0}. {1}", $i, $DisplayName)) -foregroundcolor White
    $menu.Add($i,($DisplayName))
}

到此

g_main_loop_run(loop);

主要关注项目如下

- 将$ List.count更改为$ List.Name.count,因为只有当项目在XML数据中时,$ List.Count返回空值或空值

-change -lt(小于)到-le(小于或等于),因为只有一个项目且$ i值从1开始小于永远不符合标准

-added一个switch变量来检查$ List [$ i-1] .Name是否返回null,因为它只返回一个项目。在这种情况下,请使用$ List.Name

- 使用string.Format方法输出行,不是必需的,但我发现在某些情况下它是一种更可预测的连接字符串的方法