comtel
Goto Top

CSV zu XML Probleme mit PowerShell

Hallo,
ich habe folgendes Problem.

ich habe eine CSV Datei von einem Solar-Laderegler. Diese werte würde ich gerne in meine Haussteuerung über XML einfügen.
Jetzt habe ich durch eine Anleitung von @colinardo was schönes über Powershell gefunden.
Nur leider sind die Werte in der CSV-Datei per "," getrennt und es gibt auch kommer getrennte Messwerte in der CSV-Datei.

Hat hier vielleicht jemand eine Idee, wie ich alles in XML übertragen bekomme?
Am liebsten wäre mir hier auch nur die Ausgabe in XML des letzten wertes in der Datei

Hier der Aufbau der CSV:
Date Time,Station Name,Device ID,Array Current(A),Array Voltage(V),Array Power(W),Working State,Battery Voltage(V),Battery Temp.(?),Battery Current(A),Battery SOC(%),Load Current(A),Load Power(W),Load Voltage(V),Load State,Device Temp.(?),Battery State,Charging State,Controller Working State
2017-09-17 17:05:54,Solar,1,0,53,33,4,18,Float,27,7,20,0,67,100,0,30,8,26,7,1,22,No,Normal,Normal
2017-09-17 17:06:56,Solar,1,0,53,33,4,18,Float,27,7,20,0,67,100,0,30,8,26,7,1,22,No,Normal,Normal
2017-09-17 17:07:58,Solar,1,0,57,33,2,19,Float,27,7,20,0,69,100,0,29,8,27,6,1,22,No,Normal,Normal
2017-09-17 17:08:59,Solar,1,0,57,33,2,19,Float,27,7,20,0,69,100,0,30,8,26,7,1,22,No,Normal,Normal
2017-09-17 17:10:01,Solar,1,0,57,33,2,19,Float,27,7,20,0,69,100,0,30,8,26,7,1,22,No,Normal,Normal
2017-09-17 17:11:05,Solar,1,0,57,33,2,19,Float,27,7,20,0,69,100,0,30,8,26,7,1,22,No,Normal,Normal
2017-09-17 17:12:07,Solar,1,0,57,33,2,19,Float,27,7,20,0,69,100,0,30,8,26,7,1,22,No,Normal,Normal
2017-09-17 17:13:09,Solar,1,0,57,33,3,19,Float,27,7,20,0,69,100,0,30,8,26,7,1,22,No,Normal,Normal
2017-09-17 17:14:10,Solar,1,0,57,33,3,19,Float,27,7,20,0,69,100,0,30,8,26,7,1,22,No,Normal,Normal
2017-09-17 17:15:12,Solar,1,0,56,33,4,19,Float,27,7,20,0,71,100,0,29,8,27,6,1,22,No,Normal,Normal
2017-09-17 17:16:13,Solar,1,0,56,33,4,19,Float,27,7,20,0,69,100,0,30,8,26,7,1,22,No,Normal,Normal
2017-09-17 17:17:15,Solar,1,0,56,33,4,19,Float,27,7,20,0,69,100,0,30,8,26,7,1,22,No,Normal,Normal
2017-09-17 17:18:16,Solar,1,0,56,33,4,19,Float,27,7,20,0,69,100,0,30,8,26,7,1,22,No,Normal,Normal
2017-09-17 17:19:18,Solar,1,0,56,33,4,19,Float,27,7,20,0,69,100,0,29,8,27,6,1,22,No,Normal,Normal

Hier die Werte wie Sie Original vom Regler kommen, hier sieht man auch schön die Nachkommerstellen:

solar

Hier der Aufbau des verwendeten Powershell Script von @colinardo
param(
    [string]$folder,
    [string]$delimiter = ","  
)
# Alle CSV-Dateien des Ordners durchlaufen
gci $folder -Filter "*.csv" | %{  
    write-host "Konvertiere '$($_.Fullname)' ..." -ForegroundColor Green  
    # importiere CSV-Datei als Objekt
    $csv = import-csv $_.Fullname -Delimiter $delimiter
    # Spaltennamen der CSV-Datei extrahieren
    $cols = $csv | gm -MemberType NoteProperty | select -ExpandProperty Name
    # erzeuge neues XML-Dokument
    $xml = New-Object XML
    # XML Grundgerüst laden
    $xml.LoadXml('<?xml version="1.0" encoding="utf-8"?><root></root>')  
    # Root-Knoten referenzieren
    $root = $xml.SelectSingleNode("/root")  
    # für jede Zeile der CSV-Datei ...
    foreach($line in $csv){
        # erzeuge ein neues Row-Element
        $row = $xml.CreateElement("row")  
        # für jede Spalte der Zeile erstelle ein neues Element mit dem Namen der Spalte und dem Inhalt der aktuellen Zeile
        $cols | %{
            $col = $xml.CreateElement($_)
            $col.InnerText = $line.($_)
            $row.AppendChild($col) | out-null
        }
        # füge das Row-Element im Root-Knoten ein
        $root.AppendChild($row) | out-null
    }
    # Speichere die neue XML-Datei
    $xml.Save($_.DirectoryName + "\" + $_.BaseName + ".xml")  
}

Edit:
Ich habe das Problem über ein Script auf dem Pi gelöst.
Da ich die Daten auf einem Raspberry Pi speichere.
Danke für die Hilfe!

Content-Key: 349309

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

Ausgedruckt am: 29.03.2024 um 11:03 Uhr

Mitglied: rubberman
rubberman 17.09.2017 aktualisiert um 18:08:47 Uhr
Goto Top
Warte ... eine Datei in der das Komma sowohl Listentrennzeichen, als auch Dezimaltrennzeichen ist, kann niemals eindeutig geparst werden (zumindest nicht, wenn die Werte nicht in Anführungszeichen stehen).
Also, erst mal versuchen das Übel an der Wurzel zu packen.
Wie wird die CSV Datei erstellt?
Und hast du irgendeine Möglichkeit das Listentrennzeichen (oder alternativ das Dezimaltrennzeichen) einzustellen?

Grüße
rubberman
Mitglied: comtel
comtel 17.09.2017 um 18:26:07 Uhr
Goto Top
Leider habe ich keinerlei Möglichkeiten die CSV vorher anzupassen. Das Exportierende Programm gibt keinerlei Möglichkeiten hier überhaupt irgendwas anzupassen. face-confused
Mitglied: rubberman
rubberman 17.09.2017 um 18:44:18 Uhr
Goto Top
Und die Möglichkeit, diesen Bug zu reporten, gibt's wahrscheinlich auch nicht...
Sorry, musst wohl oder übel auf die PowerSheller warten, die das Script exakt auf deine Gegebenheiten anpassen können. (Besser gesagt, neu schreiben, denn das Import-Csv Cmdlet lässt sich wohl nicht weiterhin verwenden.) Meine rudimentären Kenntnisse reichen dafür nicht.

Grüße
rubberman
Mitglied: colinardo
colinardo 17.09.2017 aktualisiert um 19:39:44 Uhr
Goto Top
Servus @comtel,
da sieht man mal wieder den Unsinn den die Jungs da bei der Entwicklung solcher Hardware zum Schluss in der Software verzapfen ...
Lässt sich aber lösen wenn die Felder immer das gleiche Dezimalformat haben, d.h. also das in den Feldern in denen es eine Kommastelle gibt diese bei jedem Wert immer ein Komma haben und die Felder mit Integerwerten später keine Nachkommastellen vorkommen, kannst das folgende von oben leicht abgeänderte Skript benutzen:
(Zeilen 7-11 ersetzen das Import-CSV des vorherigen Skripts in dem die Header-Zeile der CSV mit der letzten Zeile der CSV kombiniert wird, wobei die letzte Zeile nach Formatierungsanweisung mit Anführungszeichen versehen werden damit die PS die Spalten richtig zuordnen kann).
param([string]$folder)

# Alle CSV-Dateien des Ordners durchlaufen
gci $folder -Filter "*.csv" | %{  
    write-host "Konvertiere '$($_.Fullname)' ..." -ForegroundColor Green  
    # lese Datei als Zeilenarray ein
    $content = gc $_.Fullname
    # formatiere die letzte Zeile der Datei nach Vorgabe
    $last = $content[-1] -replace '^([^,]+),([^,]+),(\d+),(\d+,\d+),(\d+,\d+),(\d+),([^,]+),(\d+,\d+),(\d+),(\d+,\d+),(\d+),(\d+,\d+),(\d+),(\d+,\d+),([^,]+),(\d+),([^,]+),([^,]+),([^,]+)$','"$1","$2","$3","$4","$5","$6","$7","$8","$9","$10","$11","$12","$13","$14","$15","$16","$17","$18","$19"'  
    # aus Header und modifizierter letzter Zeile ein Objekt machen
    $csv = ($content,$last) | convertfrom-csv -Delimiter ","  
    # Spaltennamen der CSV-Datei extrahieren
    $cols = $csv | gm -MemberType NoteProperty | select -ExpandProperty Name
    # erzeuge neues XML-Dokument
    $xml = New-Object XML
    # XML Grundgerüst laden
    $xml.LoadXml('<?xml version="1.0" encoding="utf-8"?><root></root>')  
    # Root-Knoten referenzieren
    $root = $xml.SelectSingleNode("/root")  
    # für jede Zeile der CSV-Datei ...
    foreach($line in $csv){
        # erzeuge ein neues Row-Element
        $row = $xml.CreateElement("row")  
        # für jede Spalte der Zeile erstelle ein neues Element mit dem Namen der Spalte und dem Inhalt der aktuellen Zeile
        $cols | %{
            $col = $xml.CreateElement($_)
            $col.InnerText = $line.($_)
            $row.AppendChild($col) | out-null
        }
        # füge das Row-Element im Root-Knoten ein
        $root.AppendChild($row) | out-null
    }
    # Speichere die neue XML-Datei
    $xml.Save($_.DirectoryName + "\" + $_.BaseName + ".xml")  
}
Der Einfachheit habe ich hier einfach mal die Methode gewählt die am wenigsten Anpassung des von dir oben geposteten Skripts erfordert.

Grüße und schönen Sonntagabend
Uwe
Mitglied: comtel
comtel 17.09.2017 um 19:41:44 Uhr
Goto Top
Guten Abend,
vielen Dank für deine Unterstützung!

Noch eine kurze Frage bezüglich der Ausführung des Scipts.

Muss ich hier in der PowerShell Konsole Rechte zum Schreiben der Datei mit übergeben?

Ich habe leider noch nicht viel damit gearbeitet.
Gruß Norman
Mitglied: colinardo
colinardo 17.09.2017 aktualisiert um 19:56:40 Uhr
Goto Top
Zitat von @comtel:
Muss ich hier in der PowerShell Konsole Rechte zum Schreiben der Datei mit übergeben?
Nein, die CSV-Datei wird nur im Lesezugriff beaufschlagt. Was du natürlich sicherstellen musst ist das der Account unter dem das Skript ausgeführt wird, NTFS-Schreibrechte im Ordner der CSV-Datei hat, da hier auch die XML-Datei abgelegt wird.
Da die Powershell-Executionpolicy zum Ausführen von PS Skripten von dir bereits angepasst wurde, setze ich jetzt einfach mal voraus.
Mitglied: colinardo
colinardo 18.09.2017 aktualisiert um 19:04:59 Uhr
Goto Top
Wenns das dann war, den Beitrag bitte noch auf gelöst setzen, und Lösungen markieren. Merci.