brooklin
Goto Top

PowerShell-Skript, um Werte aus n xml-Dateien in einer txt-Datei zu sammeln

Beziehe mich auf den Beitrag
Batch Script, um Variable in allen .xml-Dateien eines Ordners zu ändern
Dazu eine Anschlußfrage:
Es gibt n xml-Dateien in einem Verzeichnis und der Wert einer ihrer Variablen soll in eine txt-Datei geschrieben werden, so daß die txt-Datei n Zeilen enthält, Bsp.:
- xml-Datei_1: Variable/Wert_1: <E K="Image_City" V="Potsdam" />

- xml-Datei_n: Variable/Wert_n: <E K="Image_City" V="Hamburg" />
Das Script soll in jeder xml-Datei "Image_City" suchen und dessen Wert in eine txt-Datei eintragen. Potsdam und Hamburg wären dann die erste und die letzte Zeile in der txt-Datei. Gesucht wird das angepaßte PowerShell-Skript aus o.g. Beitrag an die neue Fragestellung.
LG

Content-ID: 31561615143

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

Ausgedruckt am: 03.12.2024 um 18:12 Uhr

13676056485
Lösung 13676056485 17.07.2024 aktualisiert um 22:15:48 Uhr
Goto Top
N'Abend brooklin.

Wenn nur die reinen Werte aus den Files interessieren und die Files alle in einem Ordner liegen ist das mit einem Einzeiler erledigt
(Select-XML -Path "E:\Daten\*.xml" -XPath "//E[@K='Image_City']/@V").Node.Value | Set-Content -LiteralPath "e:\daten\werte.txt"    
Falls die Files in Unterordner verteilt sind, "rekursiv" dann stattdessen
(Select-XML -LiteralPath (Get-ChildItem "E:\Daten" -Recurse -File -Filter *.xml).Fullname -XPath "//E[@K='Image_City']/@V").Node.Value | Set-Content -LiteralPath "e:\daten\werte.txt"    
tio.run

Ansonsten halt ausführlich nach dem Schema des oben verlinkten Skriptes

$folder = "e:\daten"    
$txtfile = "e:\daten\werte.txt"    

$xmlfiles = Get-ChildItem -LiteralPath $folder -Recurse -File -Filter *.xml
foreach($file in $xmlfiles){
    $xml = New-Object XML
    $xml.Load($file.Fullname)
    $node = $xml.SelectSingleNode("//E[@K='Image_City']/@V")  
    If ($node){
        Add-Content -LiteralPath $txtfile -Value $node.Value
    }else{
        Write-Warning "Image_City value node not found in file '$($file.Fullname)'!"  
        Add-Content -LiteralPath $txtfile -Value ""  
    }
}
It's your choice 😉🖖.

Gruß wrk
brooklin
brooklin 17.07.2024 um 23:16:33 Uhr
Goto Top
Habe das untere Schema gleich ausprobiert - es gehte sofort (die Kurzformen dann morgen). Geniales Skript. Herzlichen Dank!!
LG
brooklin
brooklin 18.07.2024 um 12:06:15 Uhr
Goto Top
@13676056485

Nochmals Danke - gibt kleine Fehler bei genaueren Tests:
- die Langform nach obigem Schema funktioniert nicht für folgende Variablenform; die txt-Datei bleibt leer (ansonsten funktioniert es immer!):
ODER:
0,19371,2010
-> es sind m.E. die Pipes, die ein korrektes Auslesen verhindern (für ausgewählte Variable durch das übergeordnete Programm gefordert)
- der 1. Einzeiler (ohne Subfolder) funktioniert auch für die Variablenwerte mit Pipes(!) - allerdings wird in der txt-Datei immer eine Leerzeile eingeschoben, was nicht sein soll
- den 2. Einzeiler (mit Subfolder) habe ich nicht getestet, da dieser Fall bei mir nicht vorkommt

derzeitiger Stand:
- es liegen 2 Skripte für das Aus- und Einlesen von xml-Variablen vor; eigentlich müßte das für viele Nutzer von Interesse sein!
- der Workflow ist xlsx <-> txt <-> xml
- die txt ist immer ein Copy&Past-Zwischenstadium zwischen xml und Excel (wird händisch für 10 Variablen/Verzeichnis gemacht)
- [pro Verzeichnis gibt es ca. 100-1000 xml-Dateien, d.h. ebenso viele txt- bzw. xlsx-Zeilen...]

Frage:
- wäre es machbar, für beide Skripte (Ein- und Auslesen) die (mehrfachen) txt einzusparen und aus der xml gleich eine csv zu erzeugen?
- die csv sollte 11 Spalten/(bzw. 11 Semikolon...) haben: 1. Spalte der xls-Dateiname, 2.-11. Spalte=10 Variablen (können pro forma mit 'Image_City1' bis 'Image_City10' bezeichnet werden; ich würds ändern)
- der Anker wäre dann der xml-Dateiname und nicht mehr die Reihenfolge im Verzeichnis
- es kommt vor, daß eine der zehn Variablen in der xml-Datei nicht existiert => 1 zusätzl. Prüfung mit Fehlermeldung beim Einlesen mit Abbruch des Skriptes, beim Auslesen Leerzeile einfügen (ist der derzeitige Stand!)
- ich würde die beiden Langformen nutzen, weil ich wenigstens ansatzweise was erkenne (die Kurzformen sind hochelegant, aber ein Buch mit sieben Siegeln)
- ist vermutlich eine größere Bitte, hoffe, daß es keine Zumutung ist...

LG
brooklin
brooklin 18.07.2024 um 12:10:18 Uhr
Goto Top
@13676056485

Ich sehe, daß die Beispielvariablen durchs hiesige System uminterpretiert werden. Ich versuchs nochmal mit 2 Arten von Anführungszeichen:

ODER
0,19371,2010

bzw.

ODER
0,19371,2010
brooklin
brooklin 18.07.2024 um 12:11:45 Uhr
Goto Top
vllt. so:
<E K="Content_SupplementalCategories" V="1936||0,1937||1,2010||2" />  
brooklin
brooklin 18.07.2024 um 12:14:32 Uhr
Goto Top
...so ist jetzt das korrekte Aussehen der Variablen, die beim Auslesen nicht erkannt werden (vermutl. wg. der Pipes):

<E K="Content_SupplementalCategories" V="1936||0" />  
ODER
<E K="Content_SupplementalCategories" V="1936||0,1937||1,2010||2" />  
13676056485
Lösung 13676056485 18.07.2024 aktualisiert um 22:15:15 Uhr
Goto Top
Zitat von @brooklin:

...so ist jetzt das korrekte Aussehen der Variablen, die beim Auslesen nicht erkannt werden (vermutl. wg. der Pipes):

<E K="Content_SupplementalCategories" V="1936||0" />  
ODER
<E K="Content_SupplementalCategories" V="1936||0,1937||1,2010||2" />  

Nein, die Pipes interessieren nicht, was im String steht interessiert nicht ... Guckst du die Demo:
https://tio.run/##tZDNqsIwEEbX5imGbHoVm7QVFKHVgrjyhwtCEUSk6KiF2JR26nWRd6 ...

Frage:
- wäre es machbar, für beide Skripte (Ein- und Auslesen) die (mehrfachen) txt einzusparen und aus der xml gleich eine csv zu erzeugen?
Klar kein Thema ...
# zu verarbeitender ordner
$folder = "A:\brooklin"      
# Ausgabedatei (CSV)
$csvoutput = "A:\brooklin\werte.csv"  
# Array der Variablen
$variables = 'var_1s','var_2','var_3,'var_4'  
# --------------------------------
# stoppe bei Fehler
$ErrorActionPreference = 'Stop'  
# Dateien holen
$xmlfiles = Get-ChildItem -LiteralPath $folder -Recurse -File -Filter *.xml
# Dateien verarbeiten 
$result = foreach($file in $xmlfiles){
    # XML einlesen
    $xml = New-Object XML
    $xml.Load($file.Fullname)
    # Ausgabe Hashtable erstellen
    $data = [ordered]@{Filename=$file.Name}
    # Variablen durchlaufen
    foreach($var in $variables){
        # Knoten suchen
        $node = $xml.SelectSingleNode("//AL/E[@K='$var']/@V")  
        # Fallunterscheidung Knoten existiert nicht, ist leer oder hat Daten
        if (!$node){
            write-warning "Variable '$var' in '$($file.FullName)' nicht gefunden!"  
            $data.$var = "missing activity"  
        }elseif($node.Value -eq ""){  
            write-warning "Variable '$var' in '$($file.FullName)' enthält keine Daten!"  
            $data.$var = "no data"  
        }else{
            $data.$var = $node.Value
        }
    }
    # custom object aus der Hashtable erstellen
    [pscustomobject]$data
}
# Ergebnisse in CSV-Datei ausgeben
if ($result){
    $result | Export-CSV -LiteralPath $csvoutput -Delimiter ";" -NoTypeInformation -Encoding UTF8 -Force  
}

Gruß wrk
brooklin
brooklin 18.07.2024 um 21:10:13 Uhr
Goto Top
Das Skript zur Datenausgabe läuft fehlerfrei, Zeile 14 habe ich auskommentiert. Herzlichen Dank für die eingefügten Kommentare!!!

Bitte noch 2 Fallunterscheidungen berücksichtigen:
a) ein oder mehrere Variablen fehlen gänzlich
- Ist: Skript gibt Fehlermeldung aus und hält an
- Soll: Skript soll durchlaufen, "missing activity" in csv-Zeile schreiben und die Fehler auf dem Screen anzeigen
b) ein oder mehrere Variable sind leer
- Ist: keine Fehlermeldung und Skript läuft durch
- Soll: Skript soll weiterhin durchlaufen, "no data" in csv-Zeile schreiben und die Fehler auf dem Screen anzeigen

Wie heute morgen erbeten soll das Skript zur Dateneingabe (vgl. vor 14 Tagen) auch durch eine csv-Datei befüllt werden, die gleichzeitig mehrere Varibale berücksichtigt.
Fallunterscheidungen:
a) wie bisher: wenn Anzahl der xml-Dateien und Anzahl der csv-Zeilen nicht übereinstimmen, dann Fehlermeldung am Screen (wie bisher oder "values ​​and files do not match") und das Skript hält an
b) wenn die vorgegebene csv-Variable in der xml-Datei nicht vorhanden ist, dann Fehlermeldung ("missing activity" oder ähnlich) mit den fehlenden Variablen auf dem Screen ausgeben und das Skript hält an
Dann sollte es geschafft sein. Vielen Dank bis dahin.
LG
brooklin
brooklin 19.07.2024 um 12:55:55 Uhr
Goto Top
@13676056485
Gestern hatte ich vermutet, daß das Skript bei Pipes nicht funktioniert. Nein, der Fehler liegt woanders. Die Variable kann in der xml-Datei an 2 Stellen vorkommen - im Tag DL und im Tag AL. Tag AL ist der entscheidende, sonst interpretiert das Skript unter dem Tag DL die Variable, die leer ist. Bitte im Skript alle Variablen nur im Tag AL suchen, sonst funktionierts nicht durchgängig!

…
		<DL>
…
			<E K="Content_SupplementalCategories" V="" />  
…
		</DL>
		<AL>
…
			<E K="Content_SupplementalCategories" V="1916||0" />  
…
		</AL>
…

Und s.o., bitte noch 2 Fallunterscheidungen berücksichtigen:
a) ein oder mehrere Variablen fehlen gänzlich
- Ist: Skript gibt Fehlermeldung aus und hält an
- Soll: Skript soll durchlaufen, "missing activity" in csv-Zeile schreiben und die Fehler auf dem Screen anzeigen
b) ein oder mehrere Variable sind leer
- Ist: keine Fehlermeldung und Skript läuft durch
- Soll: Skript soll weiterhin durchlaufen, "no data" in csv-Zeile schreiben und die Fehler auf dem Screen anzeigen
LG