使用Powershell解析具有变量类型的XML文件

pnwntuvh  于 2023-03-23  发布在  Shell
关注(0)|答案(2)|浏览(184)

我试图从脚本中删除变量的定义,并从类似于下面的XML配置文件中读取它们:
XML文件

<?xml version="1.0" encoding="utf-8" ?>
<settings>
    <process>FALSE</process>
    <xmlDir>\\serv1\dev</xmlDir>
    <scanDir>\\serv1\dev</scanDir>
    <processedDir>\\serv1\dev\done</processedDir>
    <errorDir>\\serv1\dev\err</errorDir>
    <log>\\serv1\dev\log\dev-Log##DATE##.log</log>
    <retryDelay>5</retryDelay>
    <retryLimit>3</retryLimit>
</settings>

然后使用以下命令解析脚本中的XML:

[xml]$configFile = Get-Content $PSScriptRoot\$confFile
$settings = $configFile.settings.ChildNodes
foreach ($setting in $settings) {  
    New-Variable -Name $setting.LocalName -Value ($setting.InnerText -replace '##DATE##',(get-date -f yyyy-MM-dd)) -Force
}

这很好用,但问题是它们都是作为字符串读取的,但有些我需要作为整数读取。为了解决这个问题,我必须在创建变量后将它们更改为整数,如下所示:

$retryDelay = ([int]$retryDelay)
$retryLimit = ([int]$retryLimit)

虽然这样可以工作,但我希望在XML中有其他变量,如boolean $true / $false(并作为boolean读取),并且希望foreach能够处理它们的类型,而不是在脚本中添加额外的行。

9vw9lbht

9vw9lbht1#

首先,不要像这样读取XML文件,这会破坏XML解析器内置的编码检测,迟早会导致数据损坏。

# BAD, DO NOT USE
[xml]$configFile = Get-Content $PSScriptRoot\$confFile

正确地阅读XML文件的工作方式是这样的-创建一个新的XML对象,让它处理文件加载:

$configFile = New-Object xml
$configFile.Load("$PSScriptRoot\$confFile")

其次,我强烈建议不要从文件中创建全局变量。这是一种不好的风格,因为它可以通过盲目地覆盖现有变量来轻松破坏程序。使用散列来存储文件中的值,或者直接使用XML文件作为配置。

$config = @{}

foreach ($setting in $configFile.SelectNodes("/settings/*") ) {
    $config[$setting.Name] = $setting.InnerText
}

第三,XML没有固有的数据类型信息。在添加更多信息之前,所有内容都是字符串。一种方法可以是type属性(type="string"可以被视为默认值):

<settings>
    <process type="boolean">FALSE</process>
    <xmlDir type="string">\\serv1\dev</xmlDir>
    <scanDir type="string">\\serv1\dev</scanDir>
    <processedDir type="string">\\serv1\dev\done</processedDir>
    <errorDir type="string">\\serv1\dev\err</errorDir>
    <log type="string">\\serv1\dev\log\dev-Log##DATE##.log</log>
    <retryDelay type="int">5</retryDelay>
    <retryLimit type="int">3</retryLimit>
</settings>

当然,type属性本身没有任何意义,你需要编写代码来关注这些属性,并进行必要的类型转换(if ($setting.type -eq "boolean") { ... }等)。
第四,我相信你只需要使用JSON作为你的配置文件格式就可以了。它更容易编辑,并且它有固有的数据类型信息。

{
    "settings": {
        "process": false,
        "xmlDir": "\\\\serv1\\dev",
        "scanDir": "\\\\serv1\\dev",
        "processedDir": "\\\\serv1\\dev\\done",
        "errorDir": "\\\\serv1\\dev\\err",
        "log": "\\\\serv1\dev\\log\\dev-Log##DATE##.log",
        "retryDelay": 5,
        "retryLimit": 3
    }
}

使用ConvertFrom-JSON cmdlet分析数据。使用Get-Content -Encoding UTF8读取数据。
在处理文本文件时,使用Encoding参数是很重要的,在用Set-ContentOut-File编写文件时也是如此。在这里没有隐藏的魔法可以做正确的事情,你必须明确编码。
下面是一些关于Out-FileSet-Content行为的更深入的信息。Powershell set-content and out-file what is the difference?

pcww981p

pcww981p2#

我同意Tomalak的回答,JSON可能更适合你的用例。下面是一个实际的例子来展示你如何使用它。这是使用一个从哈希表创建的自定义对象来生成JSON并将其保存到一个文件:

$Config = [pscustomobject]@{
    Process = $false
    xmldir = '\\serv1\dev'
    scanDir = '\\serv1\dev'
    processedDir = '\\serv1\dev\done'
    errorDir = '\\serv1\dev\err'
    log = '\\serv1\dev\log\dev-Log##DATE##.log'
    retryDelay = 5
    retryLimit = 3
}

$Config | ConvertTo-Json | Out-File .\config.txt -Encoding UTF8

这将创建如下所示的JSON:

{
    "Process":  false,
    "xmldir":  "\\\\serv1\\dev",
    "scanDir":  "\\\\serv1\\dev",
    "processedDir":  "\\\\serv1\\dev\\done",
    "errorDir":  "\\\\serv1\\dev\\err",
    "log":  "\\\\serv1\\dev\\log\\dev-Log##DATE##.log",
    "retryDelay":  5,
    "retryLimit":  3
}

可以这样读:

$Settings = Get-Content .\config.txt -Encoding UTF8 | ConvertFrom-Json

由于您可以看到JSON存储变量的方式,PowerShell在读回变量时可以更好地正确键入它们。

相关问题