使用Powershell解析具有变量类型的XML文件
我试图从脚本中删除变量的定义,并从XML配置文件中读取它们,如下所示:使用Powershell解析具有变量类型的XML文件,xml,powershell,Xml,Powershell,我试图从脚本中删除变量的定义,并从XML配置文件中读取它们,如下所示: [xml]$configFile = Get-Content $PSScriptRoot\$confFile $settings = $configFile.settings.ChildNodes foreach ($setting in $settings) { New-Variable -Name $setting.LocalName -Value ($setting.InnerText -replace '
[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
}
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>
这很好,但问题是它们都是作为字符串读取的,但我需要一些作为整数。为了解决这个问题,我必须在创建变量后将其更改为整数,如下所示:
$retryDelay = ([int]$retryDelay)
$retryLimit = ([int]$retryLimit)
虽然这是可行的,但我希望XML中有其他变量,如布尔$true/$false(并以布尔形式读入),并且希望foreach能够处理它们的类型,而不是脚本中的其他行。任何线索都值得欣赏。首先,不要像这样阅读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”
可以视为默认值):
使用convertfromjson
cmdlet解析数据。使用获取内容-编码UTF8
读取它
在处理文本文件时,使用编码
参数很重要,在使用设置内容
或输出文件
编写文件时也很重要。这里没有做正确事情的隐藏魔法,您必须明确编码
下面是有关
Out File
和Set Content
行为的一些更深入的信息 首先,不要像这样读取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”
可以视为默认值):
使用convertfromjson
cmdlet解析数据。使用获取内容-编码UTF8
读取它
在处理文本文件时,使用编码
参数很重要,在使用设置内容
或输出文件
编写文件时也很重要。这里没有做正确事情的隐藏魔法,您必须明确编码
下面是有关
Out File
和Set Content
行为的一些更深入的信息 我同意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
可以这样理解:
{
"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在重新读取变量时能够更好地正确键入它们。我同意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
可以这样理解:
{
"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在重新读取变量时能够更好地正确键入它们。XML没有类型信息,除非您添加它。在不知道其他情况的情况下,每个元素和属性值都是一个字符串。也许您想使用JSON作为配置文件格式?除非您添加XML,否则它没有类型信息。在不知道其他情况的情况下,每个元素和属性值都是一个字符串。也许您想使用JSON作为配置文件格式?
Get Content
既不默认为UTF-8,也没有任何文件编码检测魔法,但这是许多人的基本假设。在读取/写入文本文件时,请始终使用显式的编码设置。有关输出文件
和设置内容
的行为和处理文件编码的详细信息,请参阅此处。@Mark Wragg非常感谢。非常感谢您的帮助。获取内容
既不是默认的UTF-8,也没有任何文件编码检测魔法,但这是许多人的基本假设。在读取/写入文本文件时,请始终使用显式的编码设置。有关输出文件
和设置内容
的行为和处理文件编码的详细信息,请参阅此处。@Mark Wragg非常感谢。非常感谢您的帮助。感谢@Tomalak提供的信息,非常感谢!我认为按照您的建议使用JSON可能更容易。我假设我可以使用foreach遍历JSON,这与解析XML的方式类似。如果像图中所示那样构造JSON,则迭代必须基于$config.settings | Get Member-Type NoteProperty |..
。关于这方面的更多解释,请参见。但是,正如我所说的,我不喜欢使用循环来填充配置文件中的变量。您的配置文件包含您的设置。你的程序知道设置什么