我正在嘗試構建一個腳本來將 XML 檔案轉換為 CSV。我開始遵循本指南https://learn.microsoft.com/en-us/answers/questions/542481/parse-xml-to-csv-help.html但我現在遇到以下情況:
我的代碼的第一部分作業正常,它將第一列寫入 CSV 檔案,但是當它通過以下迭代時,即使將值輸出到控制臺,它也不會將值寫入檔案。這是我的代碼:
[xml]$x = Get-Content C:\Users\Desktop\Policy.xml
$x.Profiles |
ForEach-Object{
$_.Profile |
ForEach-Object{
$_.Ruleset |
ForEach-Object{
Write-Host "Policy ID = " $_.ID
[PSCustomObject]@{
policyName = $_.ID
}
$_.Conditions |
ForEach-Object{
$_.condition |
ForEach-Object{
if($_.name -eq "Resource") {
Write-Host "Resource = " $_.'#text'
[PSCustomObject]@{
resource = $_.'#text'
}
}
if($_.name -eq "Action") {
Write-Host "Action = " $_.'#text'
[PSCustomObject]@{
action = $_.'#text'
}
}
if($_.name -eq "actor") {
Write-Host "actor = " $_.'#text'
[PSCustomObject]@{
actor = $_.'#text'
}
}
if($_.name -eq "child") {
Write-Host "child = " $_.'#text'
[PSCustomObject]@{
child = $_.'#text'
}
}
if($_.name -eq "number") {
Write-Host "number = " $_.'#text'
[PSCustomObject]@{
number = $_.'#text'
}
}
}
}
}
}
} | Export-Csv C:\Users\Desktop\policy.csv -NoTypeInformation
因此,直到第一個[PSCustomObject](第 10 行)它作業正常,并且 policyName 列被寫入 CSV 值及其對應的值。但是在第二個[PSCustomObject](第 19 行)它應該寫入 Resource/Action/actor/child/number 的地方,它不再寫入檔案。
將這些值添加到已經存在的正確方法是[PSCustomObject]什么?
以供參考:
XML 片段
<?xml version="1.0" encoding="UTF-8"?>
<Profiles xmlns:pcrf="nothing interesting here">
<Profile Desc="some description" ID="someid" Prio="0">
<Ruleset Class="class1" Desc="" ID="policyid1" Prio="10" active="true">
<Conditions>
<condition name="Resource" type="matchExact">resource1</condition>
<condition name="Action" type="matchExact">action1</condition>
<condition name="actor" type="matchExact">actor1</condition>
</Conditions>
</Ruleset>
<Ruleset Class="classX" Desc="" ID="policyidX" Prio="10" active="true">
<Conditions>
<condition name="Resource" type="matchExact">resource4</condition>
<condition name="Action" type="matchExact">action4</condition>
<condition name="child" type="matchExact">child1,child2</condition>
</Conditions>
</Ruleset>
</Profile>
<Profile Desc="some description" ID="someid" Prio="0">
<Ruleset Class="classY" Desc="" ID="policyidY" Prio="10" active="true">
<Conditions>
<condition name="Resource" type="matchExact">resource99</condition>
<condition name="Action" type="matchExact">action00</condition>
<condition name="child" type="matchExact">child5</condition>
<condition name="number" type="matchExact">number1</condition>
</Conditions>
</Ruleset>
</Profile>
</Profiles>
結果我得到了這個CSV:
"policyName"
"policyid1"
這是 powershell 輸出:
PS C:\Users\Desktop> .\xmltocsv.ps1
Policy ID = policyid1
Resource = resource1
Action = action1
actor = actor1
Resource = resource4
Action = action4
child = child1,child2
Resource = resource99
Action = action00
child = child5
number = number1
這是我期望得到的 CSV 檔案:
"policyName","Resource","Action","actor","child","number"
"policyid1","resource1","action1","actor1","",""
"policyidX","resource4","action4","","child1,child2",""
"policyidY","resource99","action0","","child5","number1"
uj5u.com熱心網友回復:
您的代碼的主要問題是您需要為每個<condition>元素創建一個輸出物件,其屬性值從父元素及其子元素中收集,而您正在為每個輸出的屬性[pscustomobject]創建一個單獨的物件 ( )目的; 這是一個大大簡化的解決方案:
$x.Profiles.Profile.Ruleset.Conditions |
ForEach-Object {
$outputObj = [pscustomobject] @{
# Get the policy ID from the parent node.
policyId = $_.ParentNode.ID
# The following properties are filled in below.
Resource = ''
Action = ''
actor = ''
child = ''
number = ''
}
# Loop over all child elements and fill in the property
# that corresponds to the "name" attribute with the element's inner text.
# Note that the "name" *attribute* actually shadows
# the element's type-native .Name *property*.
foreach ($el in $_.ChildNodes) {
$outputObj.($el.name) = $el.InnerText
}
# Output the resulting object
$outputObj
} |
ConvertTo-Csv # To export to a *file, use Export-Csv
如問題所示,這會產生所需的輸出。
筆記:
這會
[pscustomobject]為每個<Conditions>元素創建一個,其屬性值從父元素以及一組固定的屬性中收集,如果存在于子元素中,則根據匹配的屬性值填充這些name屬性值,使用匹配的子元素的內部文本作為屬性價值。請注意,屬性訪問會
.Profiles.Profile.Ruleset.Conditions隱式回圈多個<Profile>and<Ruleset>元素并將它們全部回傳,這要歸功于名為member-access enumeration的功能。
uj5u.com熱心網友回復:
放入表格,然后將表格保存為 CSV
using assembly System
using assembly System.Xml.Linq
$Filename = "c:\temp\test.xml"
$xDoc = [System.Xml.Linq.XDocument]::Load($Filename)
$ruleSets = $xDoc.Descendants("Ruleset").Foreach([System.Xml.Linq.XElement])
$table = [System.Collections.ArrayList]::new()
foreach($ruleSet in $ruleSets)
{
$newRow = New-Object -TypeName psobject
$id = $ruleSet.Attribute("ID").Value
$newRow | Add-Member -NotePropertyName policyName -NotePropertyValue $id
$conditions = $ruleSet.Descendants("condition").Foreach([System.Xml.Linq.XElement])
foreach($condition in $conditions)
{
$name = $condition.Attribute("name").Value
$value = $condition.Value
$newRow | Add-Member -NotePropertyName $name -NotePropertyValue $value
}
$table.Add($newRow) | Out-Null
}
$table | format-Table
uj5u.com熱心網友回復:
您必須為整行創建一個,而不是[PSCustomObject]為每一列創建一個。您可以通過首先創建有序哈希表并將其轉換為完成分配所有列值的時間來實作。 [PSCustomObject] [ordered] @{}[PSCustomObject]
為了與其他有用的答案區分開來,此答案Select-Xml用于簡化代碼。Select-Xml輸出SelectXmlInfo物件,其Node成員包含 DOM 元素,類似于您從[xml].
Select-Xml -Path Policy.xml -XPath '/Profiles/Profile/Ruleset/Conditions' | ForEach-Object {
# Create initial ordered hashtable
$row = [ordered] @{
policyName = $_.Node.ParentNode.ID
}
foreach( $name in 'Resource', 'Action', 'actor', 'child', 'number' ) {
# Add a property to the hashtable.
# The value is a SelectXmlInfo object, which Export-Csv conveniently converts to string.
$row.$name = $_.Node | Select-Xml -XPath "condition[@name='$name']/text()"
}
# Convert to PSCustomObject and output
[PSCustomObject] $row
} | Export-Csv policy.csv -NoTypeInformation
這將為您的示例 XML 輸出以下 CSV:
"policyName","Resource","Action","actor","child","number"
"policyid1","resource1","action1","actor1","",""
"policyidX","resource4","action4","","child1,child2",""
"policyidY","resource99","action00","","child5","number1"
轉載請註明出處,本文鏈接:https://www.uj5u.com/net/531439.html
標籤:xml电源外壳CSV
