将 XML 转换为 PSCustomObject
Converting XML to PSCustomObject
我正在尝试将标准 XML 文档转换为存储在一系列文件夹中的文档,将它们聚合在一起以构建自动修补系统。 XML 文档格式提供了 flexibility/ease 的最佳组合使用。不幸的是,一旦 XML 文档被格式化,PowerShell 的 XML 子系统就会区分大小写,这会给不必要的麻烦留下空间,所以我试图将导入的 XML 文档转换为 PSCustomObjects 但我卡住。
我无法找到一种方法让它检测特定 属性 是否有子节点,所以我可以再次通过 Convert-XMLtoArray
重复,这样它将转换所有 XML PSCustomObjects 的子节点。
结果:
应用程序版本 InstallType 安装程序
---------- ------ ---------- ----------
Mozilla Firefox 64.0.2 安装
预期结果:
应用程序版本 InstallType 安装程序
---------- ------ ---------- ----------
Mozilla Firefox 64.0.2 安装 {Windows 10,Windows7...}
代码:
function Convert-XmltoArray($xml) {
$Return = New-Object -TypeName 'PSCustomObject'
$XML | Get-Member -MemberType Property | ForEach {
$Property = New-Object -TypeName 'PSCustomObject'
$Name = $_.name
$Value = $XML.($Name)
if ($Value.HasChildNodes) {
foreach ($Child in $Value.ChildNodes) {
$Return | Add-Member -Type NoteProperty -Name $Child.localname -Value $($Child.'#text')
#<SomethingHere>
}
}
}
$Return
}
$Test = [XML]@"
<Package>
<Application>Java</Application>
<Version>8.2.9.23</Version>
<InstallType>Install</InstallType>
<Installers>
<Windows10>
<x86>
<File1>
<FileName>jre-8u201-windows-i586.exe</FileName>
<Parameters>/s</Parameters>
</File1>
</x86>
<x64>
<file1>
<FileName>jre-8u201-windows-x64.exe</FileName>
<Parameters>/s</Parameters>
</file1>
</x64>
<IA64>
<File1>
<FileName></FileName>
<Parameters></Parameters>
<CustomSuccessCodes></CustomSuccessCodes>
<CustomErrorCodes></CustomErrorCodes>
</File1>
</IA64>
</Windows10>
<Windows7>
<x86>
<File1>
<FileName>jre-8u201-windows-i586.exe</FileName>
<Parameters>/s</Parameters>
</File1>
</x86>
<x64>
<file1>
<FileName>jre-8u201-windows-x64.exe</FileName>
<Parameters>/s</Parameters>
</file1>
</x64>
<IA64>
<File1>
<FileName></FileName>
<Parameters></Parameters>
<CustomSuccessCodes></CustomSuccessCodes>
<CustomErrorCodes></CustomErrorCodes>
</File1>
</IA64>
</Windows7>
</Installers>
</Package>
"@
$Result = Convert-XMLToArray -xml $test
$Result
更新
终于搞明白了,居然还兼容PSv2
Function Convert-XMLtoPSObject {
Param (
$XML
)
$Return = New-Object -TypeName PSCustomObject
$xml |Get-Member -MemberType Property |Where-Object {$_.MemberType -EQ "Property"} |ForEach {
IF ($_.Definition -Match "^\bstring\b.*$") {
$Return | Add-Member -MemberType NoteProperty -Name $($_.Name) -Value $($XML.($_.Name))
} ElseIf ($_.Definition -Match "^\System.Xml.XmlElement\b.*$") {
$Return | Add-Member -MemberType NoteProperty -Name $($_.Name) -Value $(Convert-XMLtoPSObject -XML $($XML.($_.Name)))
} Else {
Write-Host " Unrecognized Type: $($_.Name)='$($_.Definition)'"
}
}
$Return
}
你永远不会得到这个……
{Windows 10,Windows7...}
…基于发布的XML样本,它不包含多个OS版本。
这是一个将填充 'Installers' 列的示例方法,但仅基于您发布的 XML 示例。
$Test = [XML]@"
<package>
<Application>Mozilla Firefox</Application>
<Version>64.0.2</Version>
<InstallType>Install</InstallType>
<Installers>
<Windows10>
<x86>
<File1>
<FileName>Firefox_Setup_64.0.2_x86.exe</FileName>
<Parameters>/s</Parameters>
</File1>
</x86>
<x64>
<file1>
<FileName>Firefox_Setup_64.0.2_x64.exe</FileName>
<Parameters>/s</Parameters>
</file1>
</x64>
<IA64>
<File1>
<FileName></FileName>
<Parameters></Parameters>
<CustomSuccessCodes></CustomSuccessCodes>
<CustomErrorCodes></CustomErrorCodes>
</File1>
</IA64>
</Windows10>
</Installers>
</package>
"@
function ConvertFrom-XmlPart($xml)
{
$hash = @{}
$xml |
Get-Member -MemberType Property |
% {
$name = $_.Name
if ($_.Definition.StartsWith("string "))
{
$hash.($Name) = $xml.$($Name)
}
elseif ($_.Definition.StartsWith("System.Object[] "))
{
$obj = $xml.$($Name)
$hash.($Name) = $($obj |
% { $_.tag }) -join "; "
}
elseif ($_.Definition.StartsWith("System.Xml"))
{
$obj = $xml.$($Name)
$hash.($Name) = @{}
if ($obj.HasAttributes)
{
$attrName = $obj.Attributes |
Select-Object -First 1 |
% { $_.Name }
if ($attrName -eq "tag")
{
$hash.($Name) = $($obj |
% { $_.tag }) -join "; "
}
else
{
$hash.($Name) = ConvertFrom-XmlPart $obj
}
}
if ($obj.HasChildNodes)
{
$obj.ChildNodes |
% { $hash.($Name).($_.Name) = ConvertFrom-XmlPart $($obj.$($_.Name)) }
}
}
}
return $hash
}
function ConvertFrom-Xml($xml)
{
$hash = @{}
$hash = ConvertFrom-XmlPart($xml)
return New-Object PSObject -Property $hash
}
ConvertFrom-XmlPart -xml $Test
# Output:
# =======
# Name Value
# ---- -----
# package {InstallType, Version, Installers, Application}
# Walking the data
$Test.package
# Output:
# =======
# Application Version InstallType Installers
# ----------- ------- ----------- ----------
# Mozilla Firefox 64.0.2 Install Installers
$Test.package.Installers
# Output:
# =======
# Windows10
# ---------
# Windows10
我正在尝试将标准 XML 文档转换为存储在一系列文件夹中的文档,将它们聚合在一起以构建自动修补系统。 XML 文档格式提供了 flexibility/ease 的最佳组合使用。不幸的是,一旦 XML 文档被格式化,PowerShell 的 XML 子系统就会区分大小写,这会给不必要的麻烦留下空间,所以我试图将导入的 XML 文档转换为 PSCustomObjects 但我卡住。
我无法找到一种方法让它检测特定 属性 是否有子节点,所以我可以再次通过 Convert-XMLtoArray
重复,这样它将转换所有 XML PSCustomObjects 的子节点。
结果:
应用程序版本 InstallType 安装程序 ---------- ------ ---------- ---------- Mozilla Firefox 64.0.2 安装
预期结果:
应用程序版本 InstallType 安装程序 ---------- ------ ---------- ---------- Mozilla Firefox 64.0.2 安装 {Windows 10,Windows7...}
代码:
function Convert-XmltoArray($xml) {
$Return = New-Object -TypeName 'PSCustomObject'
$XML | Get-Member -MemberType Property | ForEach {
$Property = New-Object -TypeName 'PSCustomObject'
$Name = $_.name
$Value = $XML.($Name)
if ($Value.HasChildNodes) {
foreach ($Child in $Value.ChildNodes) {
$Return | Add-Member -Type NoteProperty -Name $Child.localname -Value $($Child.'#text')
#<SomethingHere>
}
}
}
$Return
}
$Test = [XML]@"
<Package>
<Application>Java</Application>
<Version>8.2.9.23</Version>
<InstallType>Install</InstallType>
<Installers>
<Windows10>
<x86>
<File1>
<FileName>jre-8u201-windows-i586.exe</FileName>
<Parameters>/s</Parameters>
</File1>
</x86>
<x64>
<file1>
<FileName>jre-8u201-windows-x64.exe</FileName>
<Parameters>/s</Parameters>
</file1>
</x64>
<IA64>
<File1>
<FileName></FileName>
<Parameters></Parameters>
<CustomSuccessCodes></CustomSuccessCodes>
<CustomErrorCodes></CustomErrorCodes>
</File1>
</IA64>
</Windows10>
<Windows7>
<x86>
<File1>
<FileName>jre-8u201-windows-i586.exe</FileName>
<Parameters>/s</Parameters>
</File1>
</x86>
<x64>
<file1>
<FileName>jre-8u201-windows-x64.exe</FileName>
<Parameters>/s</Parameters>
</file1>
</x64>
<IA64>
<File1>
<FileName></FileName>
<Parameters></Parameters>
<CustomSuccessCodes></CustomSuccessCodes>
<CustomErrorCodes></CustomErrorCodes>
</File1>
</IA64>
</Windows7>
</Installers>
</Package>
"@
$Result = Convert-XMLToArray -xml $test
$Result
更新
终于搞明白了,居然还兼容PSv2
Function Convert-XMLtoPSObject {
Param (
$XML
)
$Return = New-Object -TypeName PSCustomObject
$xml |Get-Member -MemberType Property |Where-Object {$_.MemberType -EQ "Property"} |ForEach {
IF ($_.Definition -Match "^\bstring\b.*$") {
$Return | Add-Member -MemberType NoteProperty -Name $($_.Name) -Value $($XML.($_.Name))
} ElseIf ($_.Definition -Match "^\System.Xml.XmlElement\b.*$") {
$Return | Add-Member -MemberType NoteProperty -Name $($_.Name) -Value $(Convert-XMLtoPSObject -XML $($XML.($_.Name)))
} Else {
Write-Host " Unrecognized Type: $($_.Name)='$($_.Definition)'"
}
}
$Return
}
你永远不会得到这个……
{Windows 10,Windows7...}
…基于发布的XML样本,它不包含多个OS版本。
这是一个将填充 'Installers' 列的示例方法,但仅基于您发布的 XML 示例。
$Test = [XML]@"
<package>
<Application>Mozilla Firefox</Application>
<Version>64.0.2</Version>
<InstallType>Install</InstallType>
<Installers>
<Windows10>
<x86>
<File1>
<FileName>Firefox_Setup_64.0.2_x86.exe</FileName>
<Parameters>/s</Parameters>
</File1>
</x86>
<x64>
<file1>
<FileName>Firefox_Setup_64.0.2_x64.exe</FileName>
<Parameters>/s</Parameters>
</file1>
</x64>
<IA64>
<File1>
<FileName></FileName>
<Parameters></Parameters>
<CustomSuccessCodes></CustomSuccessCodes>
<CustomErrorCodes></CustomErrorCodes>
</File1>
</IA64>
</Windows10>
</Installers>
</package>
"@
function ConvertFrom-XmlPart($xml)
{
$hash = @{}
$xml |
Get-Member -MemberType Property |
% {
$name = $_.Name
if ($_.Definition.StartsWith("string "))
{
$hash.($Name) = $xml.$($Name)
}
elseif ($_.Definition.StartsWith("System.Object[] "))
{
$obj = $xml.$($Name)
$hash.($Name) = $($obj |
% { $_.tag }) -join "; "
}
elseif ($_.Definition.StartsWith("System.Xml"))
{
$obj = $xml.$($Name)
$hash.($Name) = @{}
if ($obj.HasAttributes)
{
$attrName = $obj.Attributes |
Select-Object -First 1 |
% { $_.Name }
if ($attrName -eq "tag")
{
$hash.($Name) = $($obj |
% { $_.tag }) -join "; "
}
else
{
$hash.($Name) = ConvertFrom-XmlPart $obj
}
}
if ($obj.HasChildNodes)
{
$obj.ChildNodes |
% { $hash.($Name).($_.Name) = ConvertFrom-XmlPart $($obj.$($_.Name)) }
}
}
}
return $hash
}
function ConvertFrom-Xml($xml)
{
$hash = @{}
$hash = ConvertFrom-XmlPart($xml)
return New-Object PSObject -Property $hash
}
ConvertFrom-XmlPart -xml $Test
# Output:
# =======
# Name Value
# ---- -----
# package {InstallType, Version, Installers, Application}
# Walking the data
$Test.package
# Output:
# =======
# Application Version InstallType Installers
# ----------- ------- ----------- ----------
# Mozilla Firefox 64.0.2 Install Installers
$Test.package.Installers
# Output:
# =======
# Windows10
# ---------
# Windows10