我尝试使用PowerShell 2.0将以下XML转换为CSV,我可以获取一些数据,但在尝试浏览XML对象时,我似乎无法获得数据一种格式,可以让我做一个好桌子。
我拥有的是这样的东西,有多个项目
<root type="array"> <item type="object"> <short_version type="string">11</short_version> <long_name type="string">Internet Explorer</long_name> <api_name type="string">internet explorer</api_name> <long_version type="string">11.0.9600.16384.</long_version> <latest_stable_version type="string"></latest_stable_version> <automation_backend type="string">webdriver</automation_backend> <os type="string">Windows 2012 R2</os> </item> ... </root>
我最终得到了Type,或者如果我尝试访问InnerHTML,我只得到值,但是在长字符串中。
我到目前为止:
[xml]$convertMe = Get-Content $jsonTemp
$convertMe.SelectNodes("//item") | % { $_.InnerText }
如何以漂亮的CSV格式获取此内容,如:
SHORT_VERSION,LONG_NAME,API_NAME,long_version,latest_stable_version,automation_backend,OS 11,Internet Explorer,Internet Explorer,11.0.9600.16384 ,, webdriver,Windows 2012 R2
答案 0 :(得分:3)
这是一个硬编码且很长的解决方案,但它确实有效。 :)尝试:
$xml = [xml](Get-Content .\test.xml)
$xml.root.item | Select-Object @(
@{l="short_version";e={$_.short_version."#text"}},
@{l="long_name";e={$_.long_name."#text"}},
@{l="api_name";e={$_.api_name."#text"}},
@{l="long_version";e={$_.long_version."#text"}},
@{l="latest_stable_version";e={$_.latest_stable_version."#text"}},
@{l="automation_backend";e={$_.automation_backend."#text"}},
@{l="os";e={$_.os."#text"}}) |
Export-Csv test.csv -NoTypeInformation
test.csv
"short_version","long_name","api_name","long_version","latest_stable_version","automation_backend","os"
"11","Internet Explorer","internet explorer","11.0.9600.16384.",,"webdriver","Windows 2012 R2"
另类且可能更慢的解决方案:
$xml = [xml](Get-Content .\test.xml)
#Foreach item
$xml.root.item | ForEach-Object {
$obj = New-Object psobject
$_.GetEnumerator() | ForEach-Object {
#Get all properties/elements and values
$obj | Add-Member -MemberType NoteProperty -Name $_.Name -Value $_.InnerText
}
$obj
} |
#Set property order. This also makes sure that all items exports the same properties(which a csv needs)
Select-Object short_version,long_name,api_name,long_version,latest_stable_version,automation_backend,os |
#Export to csv
Export-Csv test.csv -NoTypeInformation
答案 1 :(得分:1)
它可能有点乱,但它可以让你完全找到你正在寻找的东西。
[xml]$convertMe = Get-Content $jsonTemp
[Array]$MeConverted = $convertMe.GetElementsByTagName('item')
$Collection = @()
ForEach($Record in $MeConverted){
$Output = new-object psobject
$Record.selectnodes("*")|%{Add-Member -InputObject $Output -MemberType NoteProperty -Name $_.Name -Value $_.'#text'}
If($Collection){
$T2Keys = $Collection|gm|?{$_.MemberType -match "Property"}|Select -ExpandProperty Name
$T1Keys = $Output|gm|?{$_.MemberType -match "Property"}|Select -ExpandProperty Name
$KeysToAdd = $T2Keys|?{$T1Keys -notcontains $_}
$KeysToAdd|%{$Collection|Add-Member $_ ""}
}
$Collection += $Output
}
$Collection | Export-CSV file.csv -notype
编辑:在我看来,Frode的看起来更清晰,但我的确有一个好处,就是不必了解所有的子节点&#39;名。
编辑2:修复了明显的瑕疵,显然会有多个项目,我完全没有考虑到这一点。这只是让我的代码更大,因为我需要考虑其他潜在的属性。现在,对于每个项目,它会检查之前不在集合中的其他属性,并在将该记录添加到集合之前添加它们。
Edit3:更新了Add-Member
命令以实现向后兼容性。直到现在我还没有意识到-NotePropertyName/Value
是v3 +。
答案 2 :(得分:0)
我把一个PowerShell函数组合在一起。它假设您的XML结构很多,但它适用于您发布的内容。您只需将其传输到Out-File即可获取CSV。
Function ConvertFrom-XMLtoCSV {
[CmdletBinding()]
<#
.Synopsis
Convert a uniform XML file to CSV with element names as headers
.DESCRIPTION
Takes a uniformed XML tree and converts it to CSV based on the XPath given.
For example, assume a structure like this:
<root>
<item>
<element1>Content1</element1>
<element2>Content2</element2>
</item>
<item>
<element1>Content1</element1>
<element2>Content2</element2>
</item>
<root>
.PARAMETER Path
The path to the XML File
.PARAMETER XPath
The XPath query to the items that should be converted
.EXAMPLE
ConvertFrom-XMLtoCSV -Path .\file.xml -XPath "//item"
#>
Param (
[Parameter(Mandatory=$true,ValueFromPipelineByPropertyName=$true,Position=0)][String] $Path,
[Parameter(Mandatory=$true,ValueFromPipelineByPropertyName=$true,Position=1)][String] $XPath
)
Begin {
if (Test-Path $Path) {
[XML] $XML = Get-Content $Path -Raw
} else {
Throw [System.IO.FileNotFoundException] "XML file was not found at the given path"
}
$NodeCount = $XML.SelectNodes($XPath).Count
$FileHeaders = [System.String]::Join(",",$($XML.SelectNodes("$XPath[1]/node()") | ForEach-Object { $_.ToString()}))
$Content = @()
}
Process {
$Content += $FileHeaders
For ($i = 1; $i -le $NodeCount; $i++) {
$Content += [System.String]::Join(",",$($xml.SelectNodes("$XPath[$i]/node()") | ForEach-Object {$_."#text"}))
}
return $Content
}
}