oliswiss
Goto Top

PowerShell XML ergänzen-mutieren mittels Abfrage externer Daten

Seit zwei Wochen arbeite ich an PS-Scripts, die primär folgendes tun (und das tun sie bisher auch face-smile):
1. XML-file von Web- oder FTP-Server holen
2. XML mit seinem Schema (XSD) validieren
3. XML als CSV (UTF-8) ausgeben
4. CSV mittel Aufruf eines spezifischen SQL-Import-Tools in SQL importieren

Nun steh ich vor Aufaben, die ich als PS-Neuling und Nicht-Entwickler ganz sicher nicht alleine hinbekomme! Ich hoff jetzt mal drauf, dass sich hier gute Seelen tummeln die mir dabei weiterhelfen können. Der Gesamtprozess ist ingesamt komplex und es wäre zu aufwendig hier alles wiederzugeben. Ich versuche deshalb nachfolgend zu erläutern, mit welchen Schritten/Prozessen ich meine PS-Scripts erweitern möchte.

Also, Ausgangslage ist das XML-file welches ich runterlade ... einfaches Beispiel:
<?xml version="1.0" encoding="UTF-8"?>  
<PRODUCTS>
    <SPAREPARTS>
        <FATHER-LIEF-NR>02_HRZ3100</FATHER-LIEF-NR>
        <FATHER-HERST-NR>HRZ3100</FATHER-HERST-NR>
        <FATHER-HERST-NAME>BRAND1</FATHER-HERST-NAME>
        <PART-LIEF-NR>02_HRZ2544</PART-LIEF-NR>
        <PART-HERST-NR>HRZ2544</PART-HERST-NR>
        <PART-HERST-NAME>BRAND1</PART-HERST-NAME>
    </SPAREPARTS>
    <SPAREPARTS>
        <FATHER-LIEF-NR>02_249310023</FATHER-LIEF-NR>
        <FATHER-HERST-NR>949310023682021</FATHER-HERST-NR>
        <FATHER-HERST-NAME>BRAND2</FATHER-HERST-NAME>
        <PART-LIEF-NR>13_EFLB1303</PART-LIEF-NR>
        <PART-HERST-NR>EFLB1303</PART-HERST-NR>
        <PART-HERST-NAME>BRAND14</PART-HERST-NAME>
    </SPAREPARTS>
    <SPAREPARTS>
        <FATHER-LIEF-NR>02_KZU310056</FATHER-LIEF-NR>
        <FATHER-HERST-NR>KZU310056</FATHER-HERST-NR>
        <FATHER-HERST-NAME>BRAND22</FATHER-HERST-NAME>
        <PART-LIEF-NR>13_HRZ2274</PART-LIEF-NR>
        <PART-HERST-NR>HRZ2274</PART-HERST-NR>
        <PART-HERST-NAME>BRAND1</PART-HERST-NAME>
    </SPAREPARTS>
   ... so weiter von einigen bis mehrere tausend, je nach Quelle
</PRODUCTS>
Beim CSV-Output sieht das dann so aus:
"FATHER-LIEF-NR";"FATHER-HERST-NR";"FATHER-HERST-NAME";"PART-LIEF-NR";"PART-HERST-NR";"PART-HERST-NAME"  
"02_HRZ3100";"HRZ3100";"BRAND1";"02_HRZ2544";"HRZ2544";"BRAND1"  
"02_249310023";"949310023682021";"BRAND2";"13_EFLB1303";"EFLB1303";"BRAND14"  
"02_KZU310056";"KZU310056";"BRAND22";"13_HRZ2274";"HRZ2274";"BRAND1"  
Dazu folgende Erklärung:
Die drei Zeichen inkl. underline von links bei den Felder mit "...LIEF-NR" ist immer das Prefix des Datenlieferanten, welches seine interne Warengruppe reflektiert. Diese Strings inkl. dieses Prefix verwende ich direkt in der DB als "Lieferantenartikelnummer".
Der Lieferant verbiegt aufgrund der Tatsache, dass sein System im Artikelnummernfeld nur eine sehr begrenzte Anzahl an Zeichen zulässt, die ganze Logik für diese Artikelnummern. Und das ist zugleich eines der Probleme, dem ich durch eine schlaue Lösung Herr werden möchte. Das Problem was ich meine sieht man auf der zweiten Datenzeile des CSV-Outputs > der String im Feld "FATHER-LIEF-NR" ab dem underline entspricht nicht dem Wert in "FATHER-HERST-NR". Im Normalfall wäre das so, aber dort wo die "...-HERST-NR" inkl. seinem Prefix zu lang ist macht er dann irgendwas face-sad

Soweit so gut - der String in "...HERST-NR", also die Originale Hersteller-Artikelnummer, wird in meiner DB ursprünglich als meine eigene Artikelnummer importiert und verwendet. Das hat nun aber zu Doubletten geführt, weil verschiedene BRAND's (Hersteller) z.t. gleiche Artikelnummern führen! Sehr schlecht!
Meine Lösung ist nun die, dass ich jedem BRAND einen Prefix + Bindestrich zuteile; wäre beispielsweise für "Coca-Cola" ein "CCL-". Dann führe ich alle möglichen Hersteller in einer EXCEL- oder CSV Tabelle, deren erste zwei Spalten dann wie folgt ausschauen:
HERSTELLERNAME | HERSTELLER-PREFIX | 
Und jetzt kommt das Stück PS-Script, von dem ich nicht mal ansatzweise wüsste wie das aussehen könnte!
Im SP-Script hab ich die XML-Datei mit GET-CONTENT geöffnet ...un das Ding sollte jetzt folgendes tun:
1. in der XML-Datei eine "Spalte" (Child) mit dem Namen "MY-FATHER-NR" und eine mit "MY-PART-NR" erstellen
2. die Excel/CSV-Quelle (ich nenn's mal PREFIX-DB) mit den HERSTELLER-PREFIX Definitionen für Zugriff öffnen ...
3. Bei jedem XML-Datensatz den String in "FATHER-HERST-NAME" in der PREFIX-DB suchen und dann ...
3a. in der neuen XML-Spalte "MY-ART-NO" den Prefix + Bindestrich + FATHER-HERST-NR reinschreiben.
3b. in der XML-Spalte "FATHER-HERST-NR" den Hersteller-Namen (also String aus "FATHER-HERST-NAME") + Leerschlag + FATHER-HERST-NR reinschreiben
4. Wie bei 3. aber nun beim "PART ..."

Der erste Datensatz in der XML würde dann jetzt so aussehen (bei Annahme "BRN" ist Prefix für "BRAND1":
    <SPAREPARTS>
        <MY-FATHER-NR>BRN-HRZ3100</MY-FATHER-NR>
        <FATHER-LIEF-NR>02_HRZ3100</FATHER-LIEF-NR>
        <FATHER-HERST-NR>BRAND1 HRZ3100</FATHER-HERST-NR>
        <FATHER-HERST-NAME>BRAND1</FATHER-HERST-NAME>
        <MY-PART-NR>BRN-RZ2544</MY-PART-NR>
        <PART-LIEF-NR>02_HRZ2544</PART-LIEF-NR>
        <PART-HERST-NR>BRAND1 HRZ2544</PART-HERST-NR>
        <PART-HERST-NAME>BRAND1</PART-HERST-NAME>
    </SPAREPARTS>
Die ganze Darstellung ist vereinfacht - ich habe da auch XML-Files mit viel mehr Inhalt (Nodes).

Hat in diesem Universum irgend jemand eine Idee oder zumindest Ansätze wie man sowas löst?
Vielen herzlichen Dank schon mal face-smile

Content-Key: 438456

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

Printed on: April 20, 2024 at 11:04 o'clock

Mitglied: 139374
Solution 139374 Apr 10, 2019, updated at Apr 12, 2019 at 13:36:53 (UTC)
Goto Top
Wieso erst noch in der XML abändern, mach das doch gleich in den Objekten und gebe es dann als CSV aus face-smile.
$csvdb = Import-CSV 'D:\prefixdb.csv' -Delimiter ";"  
$xml = [xml](gc 'D:\import.xml')  
$items = @()
foreach($part in $xml.PRODUCTS.SPAREPARTS){
    $prefix = $csvdb | ?{$_.HERSTELLERNAME -eq $part.'FATHER-HERST-NAME'} | select -Expand 'HERSTELLER-PREFIX'  
    $items += [pscustomobject]@{
        'MY-FATHER-NR' = "$prefix-$($part.'FATHER-HERST-NR')"  
        'FATHER-LIEF-NR' = $part.'FATHER-LIEF-NR'  
        'FATHER-HERST-NR' = "$($part.'FATHER-HERST-NAME') $($part.'FATHER-HERST-NR')"  
        'FATHER-HERST-NAME' = $part.'FATHER-HERST-NAME'  
        'MY-PART-NR' = "$prefix-$($part.'PART-HERST-NR')"  
        'PART-LIEF-NR' = $part.'PART-LIEF-NR'  
        'PART-HERST-NR' = "$($part.'PART-HERST-NAME') $($part.'PART-HERST-NR')"  
        'PART-HERST-NAME' = $part.'PART-HERST-NAME'  
    }
} 
$items  | export-csv 'd:\export.csv' -Delimiter ";" -NoType -Encoding UTF8  
Eine Prüfung ob Prefix nicht vorhanden hast wirst du hoffentlich noch selbst mit einem if() hinbekommen face-smile, das lass ich dir als Hausaufgabe.
Member: oliswiss
oliswiss Apr 12, 2019 at 13:09:36 (UTC)
Goto Top
Heyyy timeout, das ist Hammer! Auch wenns jetzt viel langsamer läuft ... damit kann ich endlich genau das rausschreiben was ich haben möchte face-smile

Kurze Frage noch:
Kann ich innerhalb von z.Bsp. ...
'FATHER-HERST-NR' = "$($part.'FATHER-HERST-NAME') $($part.'FATHER-HERST-NR')"  
... eine IF-Abfrage starten? Läuft immer auf Fehler bei mir mit ...
'PRIN_ART_NO' = IF($($part.'SupplierCode') = empty){"$prefix-$($part.'Code')"}ELSE{"$prefix-$($part.'SupplierCode')"}  
Was mach ich da falsch?

PS: die "Hausaufgabe" muss ich auch noch lösen face-smile

Danke Dir!!!
Mitglied: 139374
Solution 139374 Apr 12, 2019 updated at 13:42:24 (UTC)
Goto Top
'PRIN_ART_NO' = @{$true="$prefix-$($part.Code)";$false="$prefix-$($part.SupplierCode)"}[($part.SupplierCode -eq "")]  

p.s. oben noch beschleunigt.
Member: oliswiss
oliswiss Apr 12, 2019 at 14:48:20 (UTC)
Goto Top
DANKEEEEE! face-smile
Habs begriffen von wegen wie man einfache IF's baut ...
Wie verknüpfe ich mehrere Abfragen im IF?
Mitglied: 139374
Solution 139374 Apr 12, 2019 updated at 18:04:57 (UTC)
Goto Top
Wie verknüpfe ich mehrere Abfragen im IF?
Wie wär's zwischendurch mal mit Handbuch lesen?

-and
-or

https://goo.gl/search/powershell+logical+operators
Member: oliswiss
oliswiss Apr 12, 2019 at 20:04:44 (UTC)
Goto Top
Danke, das war mir klar, hab mich da zuwenig klar ausgedrückt.
Was ich suche ist das Konstrukt, was zu nicht nur einer von zwei (true/false) Ergebnissen führt, sondern zu einer von vielen.
Mitglied: 139374
Solution 139374 Apr 13, 2019 updated at 05:39:38 (UTC)
Goto Top
If () {

}elseif (){

}elseif (){

}else(){

}

Oder

Switch($var){
'bla' {}
'blub' {}
}
https://www.windowspro.de/script/if-else-switch-bedingte-anweisungen-pow ...

Oder eben wie ich dir oben schon gezeigt habe mit einer Hashtable mit mehreren Wertpaaren welche anhand des Ergebnisses in den eckigen Klammern ausgewählt wird.
'PRIN_ART_NO' = @{'Ergebnis1'='Wert1';'Ergebnis2'='Wert2';'Ergebnis3'='Wert3'}[$part.WasauchimmerdieErgebnisseliefert]  
Member: oliswiss
oliswiss Apr 13, 2019 at 07:56:19 (UTC)
Goto Top
Sorry, da scheint mir echt ne Hirnwindung zu fehlen!?
Hab ich jetzt folgende Abfrage die nur true oder false zurückliefert ...
'PRIN_LIEFERSTATUS' = @{$true="Ausverkauf";$false=""}[($part.sa_stockCouleur -eq "S") -and ($part.Stock -gt 0)]  
"$part.sa_stockCouleur" kann aber auch andere Werte als "S" anliefern und "$part.Stock" liefert einen immer Integer-Wert an.
Du schreibst ...
... = @{'Ergebnis1'='Wert1';'Ergebnis2'='Wert2';'Ergebnis3'='Wert3'}[$part.WasauchimmerdieErgebnisseliefert]  
Wie notiere/adressiere ich in der eckigen Klammer denn alle möglichen Abfragen nacheinander und weise diese den Ergebnissen zu?

Beispiel:
'PRIN_LIEFERSTATUS'   
... soll Wert "Ausverkauf" erhalten, WENN $part.sa_stockCouleur = S UND $part.Stock = 0 (das geht ja so mit true/false-Version oben)
hinzu kommen jetzt aber einige andere Varianten ...
... soll Wert "im Rückstand" erhalten, WENN $part.sa_stockCouleur = R UND $part.Stock = 0 oder
... soll Wert "nur auf Bestellung" erhalten, WENN $part.sa_stockCouleur = T UND $part.Stock = 0 oder
... soll Wert "solange Vorrat" erhalten, WENN $part.sa_stockCouleur = R UND $part.Stock > 0 usw.

Ich muss doch irgendwie die Abfrage "($part.sa_stockCouleur -eq "S") -and ($part.Stock -gt 0)" als Variable deklarieren und das Rückgabeergebnis in diese Variable schreiben um dann bei Eintreffen den richtigen Wert einzufügen ...!?
Mitglied: 139374
Solution 139374 Apr 13, 2019 updated at 08:15:02 (UTC)
Goto Top
Gut, diese Bedingung war mir ja nicht bekannt, das mit der Hashtable funktioniert hier dann nicht das geht nur um das Ergebnis einer Bedingung zu erhalten.
Für das was du da hast ist das If...Elseif..Else...Endif Konstrukt das Richtige, damit kannst du beliebig viele Elseif Zweige benutzen und einer Variablen den gewünschten Wert zuweisen. Das setzt du vor das CustomObjekt und deklarierst eine Variable in der du den gewünschten Inhalt ausgibst. Im CustomObjekt setzt du dann passend die gerade erzeugte Variable ein
'PRIN_LIEFERSTATUS' = $variable  
Fertig.
Member: oliswiss
oliswiss Apr 17, 2019 at 17:16:32 (UTC)
Goto Top
Hey danke, Du hast mir echt sehr geholfen!!!
Hast Du auch ne Ahnung wie ich alle Strings einer Tabellenspalte in SQL-Server abfrage, diese dann mit Strings der ersten Spalte im CSV-file (BRANDDB) vergleiche und das DIFF in ein neues csv-file rausschreibe?

DIFF.CSV-ErgebnisOutput: WENN in SQL vorhanden, aber in BRANDDB.csv nicht:
SPALTE1 = STRING
SPALTE2 = "Fehlt in BRANDDB"

DIFF.CSV-ErgebnisOutput: WENN in SQL nicht vorhanden, aber in BRANDDB.csv gefunden:
SPALTE1 = STRING
SPALTE2 = "Fehlt in SQLDB"