axelskywalker
Goto Top

XML in CSV umwandeln - Powershell

Guten Abend.

Ich benötige Hilfe bei der Umwandlung von einer .xml Datei zu .csv mittels Powershell.

Ich habe hier schon einige Beiträge dazu gefunden und habe auch schon grob was programmiert. Da ich aber nie mit Powershell gearbeitet habe, komme ich jetzt nicht weiter.
Im Prinzip funktioniert es, nur in der falschen Reihenfolge. Ich komme mit der XML Struktur nicht zurecht.

Wenn ich die XML Datei so in Excel rein ziehe, dann habe ich die Überschriften der Tabellen alle in der richtigen Reihenfolge. Obwohl die in der XML scheinbar verstreut sind.
Wandel ich das per Powershell, schaffe ich es nicht, das die Überschriften alle nebeneinander sind. Bisschen schwer zu erklären.


Ich kann nicht die ganze Datei anhängen, die ist sehr groß. Daher versuche ich mittels Bilder die Struktur darzustellen. Wenn ich die Datei sonst anders verfügbar machen kann, gebt mir bitte einen Hinweis.

Das wäre alle Überschriften (Spalten)
Country	MainBmCode	Month	Year	Currency	NumberOfMakes	NumberOfSites	ExtractionDate	ExtractionTime	BeginFiscalYear	Make	MakeCode	Make2	Site	BmCode	Account	Make3	Site4	Origin	SalesChannel	CostCarrier	DriveSystem	CostAccountingString	Decimals	OpeningBalance	Period01	Period02	Period03	Period04	Period05	Period06	Period07	Period08	Period09	Period10	CumulatedYear

Wie man auf dem Bild xml2csv1 sehen kann. Steht nur ein Teil der Überschriften in <Header>. Der Rest kommt woanders her. Das ist das, was ich nicht verstehe.

Bild xml2csv1 zeigt die grobe Struktur
Bild xml2csv2 zeigt <MakeListEntry> wobei Make und MakeCode und Site auch Überschriften sind.
Bild xml2csv3 zeigt <BmCodeEntry>
Bild xml2csv4 zeigt <RecordList> was den meistens Inhalt ausmacht.

Blickt da irgendjemand durch ?

Hier mal mein Code. Der lädt die XML Datei und speichert mir das in einer .csv
[xml]$inputFile = Get-Content "C:\Users\Benutzer\Desktop\XML_Test.xml"  

$inputFile.HbvData.Header | ConvertTo-Csv -NoTypeInformation -Delimiter ";" | Set-Content -Path "C:\Users\Benutzer\Desktop\new.csv" -Encoding UTF8  
$inputFile.HbvData.MakeList.MakeListEntry | ConvertTo-Csv -NoTypeInformation -Delimiter ";" | Add-Content -Path "C:\Users\Benutzer\Desktop\new.csv" -Encoding UTF8  
$inputFile.HbvData.BmCodeList.BmCodeEntry | ConvertTo-Csv -NoTypeInformation -Delimiter ";" | Add-Content -Path "C:\Users\Benutzer\Desktop\new.csv" -Encoding UTF8  
$inputFile.HbvData.RecordList.Record | ConvertTo-Csv -NoTypeInformation -Delimiter ";" | Add-Content -Path "C:\Users\Benutzer\Desktop\new.csv" -Encoding UTF8  



Das Problem ist jetzt, das der die Daten nicht in der richtigen Reihenfolge ausgibt. Ich habe erst die Überschriften aus dem Header. Die nächsten Überschriften aus MakeListEntry schreibt er dann darunter. Was auch logisch ist, da ich das in 4 Zeilen programmiert habe. Wie kann ich das jetzt zusammenbringen?
xml2csv1
xml2csv2
xml2csv3

Content-Key: 1728966946

Url: https://administrator.de/contentid/1728966946

Printed on: April 24, 2024 at 00:04 o'clock

Mitglied: 149569
149569 Jan 17, 2022 updated at 16:11:11 (UTC)
Goto Top
Soll-Zustand als Beispiel wäre hilfreich, sonst weis wohl keiner wie du die Einträge kombiniert haben willst ...

Dateien kostenlos hochladen mit Freigabelink kannst du heutzutage überall, z.B. hier
https://wetransfer.com/

Natürlich vorher anonymisieren!
Member: colinardo
Solution colinardo Jan 18, 2022 updated at 15:41:59 (UTC)
Goto Top
Servus @Axelskywalker, willkommen auf Administrator.de!
Wie mein Vorredner schon erwähnt hat wäre der gewünschte Soll-Zustand hilfreich und evt. auch eine gekürzte anonymisierte Demo-Datei (kannst du mir bei Bedarf auch per PN einen Link zuschicken).

Ich bemühe aber trotzdem erst mal meine Glaskugel, vielleicht ist das Ergebnis schon das was du benötigst
# xml file path
$xmlfile = 'D:\Data\demo.xml'  
# csv file path
$csvfile = 'D:\Data\export.csv'  
# load xml
$xml = New-Object XML; $xml.Load($xmlfile)
# xpath expression contains Nodes to be combined
$node_xpath = "//MakeListEntry|//BmCodeEntry|//Record"  
# extract all headers
[string[]]$headers = $xml.SelectNodes("//Header|$node_xpath") | %{($_ | gm -M Property).Name} | select -Unique  

# create objects for each node
$result = foreach($node in $xml.SelectNodes($node_xpath)){
    # create new object from header data and all headers
    $obj = $xml.HbvData.Header | select $headers
    # fill object properties with node data
    $node | gm -M Property | %{
        $obj.($_.Name) = $node.($_.Name)
    }
    # output object
    $obj
}
# export result as csv
$result | export-csv $csvfile -Delimiter ";" -NoType -Encoding UTF8  

Grüße Uwe
Member: Axelskywalker
Axelskywalker Jan 18, 2022 at 19:36:25 (UTC)
Goto Top
Schon mal vielen Dank für deine Mühe Uwe. Wirklich großartig das ich so schnell eine Antwort bekommen habe.
Das geht schon in die richtige Richtung. Das einzige was jetzt noch anders ist, ist die Spaltenreihenfolge.

Im Original habe ich die Spalten
Country MainBmCode Month Year Currency NumberOfMakes NumberOfSites ExtractionDate ExtractionTime BeginFiscalYear Make MakeCode Make2 Site BmCode Account Make3 Site4 Origin SalesChannel CostCarrier DriveSystem CostAccountingString Decimals OpeningBalance Period01 Period02 Period03 Period04 Period05 Period06 Period07 Period08 Period09 Period10 CumulatedYear

Und nach dem Export habe ich die Spalten in dieser Reihenfolge.

BeginFiscalYear	Country	Currency	ExtractionDate	ExtractionTime	MainBmCode	Month	NumberOfMakes	NumberOfSites	Year	Make	MakeCode	BmCode	Site	Account	CostAccountingString	CostCarrier	CumulatedYear	Decimals	DriveSystem	OpeningBalance	Origin	Period01	Period02	Period03	Period04	Period05	Period06	Period07	Period08	Period09	Period10	SalesChannel

Wenn man das noch hinbekommt dann wäre es schon perfekt.
Member: colinardo
Solution colinardo Jan 18, 2022, updated at Jan 19, 2022 at 17:58:20 (UTC)
Goto Top
Die Reihenfolge kannst du leicht selbst anpassen indem du in der letzten Zeile einfach ein select dazwischen schaltest und darin deine Spalten in der gewünschten Reihenfolge als Array angibst
$result | select Country,MainBmCode,Month,..... | export-csv  ...............
Die Punkte sind natürlich nur Platzhalter für deine Überschriften die ich jetzt nicht alle aufzählen wollte und den Rest von Export-CSV habe ich weggelassen das bleibt ja alles gleich.

Grüße Uwe

Wenns das dann war, den Beitrag bitte noch auf gelöst setzen, und Lösungen markieren. Merci.
Member: Axelskywalker
Axelskywalker Jan 19, 2022 at 20:22:23 (UTC)
Goto Top
Vielen Dank, das funktioniert einwandfrei.
Hier nochmal das Script komplett damit man das nachvollziehen kann.

# xml file path
$xmlfile = 'C:\Users\Desktop\XML.xml'  
# csv file path
$csvfile = 'C:\Users\Desktop\export.csv'  
# load xml
$xml = New-Object XML; $xml.Load($xmlfile)
# xpath expression contains Nodes to be combined
$node_xpath = "//MakeListEntry|//BmCodeEntry|//Record"  
# extract all headers
[string[]]$headers = $xml.SelectNodes("//Header|$node_xpath") | %{($_ | gm -M Property).Name} | select -Unique  

# create objects for each node
$result = foreach($node in $xml.SelectNodes($node_xpath)){
    # create new object from header data and all headers
    $obj = $xml.HbvData.Header | select $headers
    # fill object properties with node data
    $node | gm -M Property | %{
        $obj.($_.Name) = $node.($_.Name)
    }
    # output object
    $obj
}
# export result as csv

$result | select Country, MainBmCode, Month, Year, Currency, NumberOfMakes, NumberOfSites, ExtractionDate, ExtractionTime, BeginFiscalYear, Make, MakeCode, Make2, Site, BmCode, Account, Make3, Site4, Origin, SalesChannel, CostCarrier, DriveSystem, CostAccountingString, Decimals, OpeningBalance, Period01, Period02, Period03, Period04, Period05, Period06, Period07, Period08, Period09, Period10, CumulatedYear | export-csv $csvfile -Delimiter ";" -NoType -Encoding UTF8