Benutzer mit den meisten Antworten
XML-Element über den Namen ansprechen

Frage
-
Gutem Morgen,
leider bin ich nicht so der XML-Held und weiß daher auch nicht so richtig, wie ich nach einer Lösung suchen soll.
Meine XML-Datei hat den folgenden Aufbau:
<?xml version="1.0" encoding="utf-8"?> <System> <Umgebungen> <Umgebung Name="Testanlage"> <Mandant Name ="Aussendienst"> <Server1>xyz1</Server1> <Server2>xyz2</Server2> </Mandant> <Mandant Name="Innendienst"> <Server1>xyz3</Server1> <Server2>xyz4</Server2> </Mandant> </Umgebung> <Umgebung Name="Produktion"> <Mandant Name ="Aussendienst"> <Server1>abc1</Server1> <Server2>abc2</Server2> </Mandant> <Mandant Name="Innendienst"> <Server1>abc3</Server1> <Server2>abc4</Server2> </Mandant> </Umgebung> </Umgebungen> </System>
Diese XML-Datei importiere ich in PowerShell. Das funktioniert; alles gut soweit.
Jetzt möchte ich gerne in meiner Variablen eine Umgebungen und einen Mandant ganz gezielt über den Namen ansprechen. Leider habe ich keine Idee, wie das funktioniert. Tagelanges Suchen und ausprobieren ist leider erfolglos geblieben und auch meine Kollegen wissen keinen Rat. Ich stelle mir das so vor, wie bei Excel, wenn ich ein Arbeitsblatt über den Namen anspreche: Worksheets("<Arbeitsblattname>"). Also so ungefähr:
<Variable>.System.Umgebungen.Umgebung('Testanlage').Mandant('Innendienst').Server1
Leider funktioniert es so nicht.
Wie komme ich am Einfachsten an meinen Server1?Für jeden Lösungsvorschlag oder -ansatz bin ich dankbar.
Vielen Dank und viele Grüße
Sabine
Antworten
-
Hallo,
so auf die schnell würde ich das wie folgt lösen:
[xml]$xml = Get-Content C:\Temp\xml.xml ($xml.System.Umgebungen.Umgebung | Where-Object {$_.Name -eq "Produktion"}).Mandant.Server1
gibt aber bestimmt eine eleganter Lösung.
lg
- Als Antwort vorgeschlagen Denniver ReiningMVP, Moderator Samstag, 3. November 2018 11:04
- Als Antwort markiert Denniver ReiningMVP, Moderator Dienstag, 6. November 2018 12:10
-
Geht schon - mit XPath und Select-XML:
$TestAussen = select-xml $xmldoc -XPath "//System//Umgebungen//Umgebung[@Name='Testanlage']//Mandant[@Name='Aussendienst']"
Aber aufpassen, das ist komplett case sensitive. Es hat sich bewährt, Node- und Attributnamen komplett klein zu schreiben und nur Attributwerte bzw. Textinhalte bei Bedarf "richtig". Wenn Du alleine schon Attributinhalte case-insensitive suchen willst, mußt Du ne komplette Umwandlung in Klein- oder Großbuchstaben machen und erst dann suchen.
Und es hat sich auch bewährt, für einfaches Skripting auf Elemente wie <Server1>abc1</Server1> zu verzichten und stattdessen <server1 name="abc1"/> zu verwenden :)
Oder noch besser <server num="1" name="abc"/>. Node-Elemente möglichst generisch, differenzieren durch Attribute.
Greetings/Grüße, Martin - https://mvp.microsoft.com/en-us/PublicProfile/5000017 Mal ein gutes Buch über GPOs lesen? - http://www.amazon.de/Windows-Server-2012--8-Gruppenrichtlinien/dp/3866456956 Good or bad GPOs? My blog - http://evilgpo.blogspot.com And if IT bothers me? Coke bottle design refreshment - http://sdrv.ms/14t35cq
- Als Antwort vorgeschlagen Denniver ReiningMVP, Moderator Samstag, 3. November 2018 11:05
- Als Antwort markiert Denniver ReiningMVP, Moderator Dienstag, 6. November 2018 12:10
-
Wie immer führen viele Wege zum Ziel.
Noch mal zurück auf Anfang:
XML bietet dir nur eine Schema-Definition ähnlich eine SQL-Tabelle, mit dem Unterschied, dass man eine XML-Knoten-Hierarchie bilden kann.Alle XML-Namen "<Name Attr1="" Attr2="">....</Name>" sind wie Spaltennamen zu sehen.
Die Direktansprache funktioniert natürlich nur über die Knoten-/Attributnamen.Wenn man nach Inhalten sucht, kommst du halt um Suchfunktionen nicht herum.
Alternativ kannst du jedoch ebenso statt "<Mandant>" auch einen Knoten "<Innendienst>" definieren, der dann direkt ansprechbar ist. Das macht die XML-Verarbeitung aber ggf. unflexibel.
<?xml version="1.0" encoding="utf-8"?> <System> <Umgebungen> <Testanlage> <Aussendienst> <Server Name="xyz1" /> <Server Name="xyz2" /> </Aussendienst> <Innendienst> <Server Name="xyz3" /> <Server Name="xyz4" /> </Innendienst> </Umgebung> <Produktion> <Aussendienst> <Server Name="xyz5" /> <Server Name="xyz6" /> </Aussendienst> <Innendienst> <Server Name="xyz7" /> <Server Name="xyz8" /> </Innendienst> </Produktion </Umgebungen> </System>
Somit hast du dann wieder die Ansprache
$xml.Umgebungen.Testanlage.Aussendienst.Server
Wobei Server dann eben als Array ansprechbar sind.
$xml.Umgebungen.Testanlage.Aussendienst.Server[0].Attributes["Name"]$xml.Umgebungen.Testanlage.Aussendienst.Server.Count = Anzahl Knoten.
Das Ganze geht natürlich auch variabel, da sichdie Knotennamen auchauslesen lassen:$xml.Umgebungen.Count = Anzahl Knoten
$xml.Umgebungen[0].Name = Testanlage
$xml.Umgebungen[1].Name = Produktion$Name = $xml.Umgebungen[0].Name
$xml.Umgebungen[$Name].Innendienstusw. usf.
Noch ein Unterschied:
select-xml liest ein Dokument ein, durchsucht es, liefert das Ergebnis und verwirft das Dokument dann wieder.
Jedes neue select-xml wiederholt den gesamten Vorgang.
select-xml kann man dann verwenden, wenn man nur 1 Mal auf das Dokument zugreifen will.Liest man das Dokument aber direkt ein, kann man es mittels "$xml.SelectNodes" oder "$xml.SelectSingleNode" immer wieder durchsuchen.
- Als Antwort vorgeschlagen Denniver ReiningMVP, Moderator Samstag, 3. November 2018 11:05
- Als Antwort markiert Denniver ReiningMVP, Moderator Dienstag, 6. November 2018 12:10
Alle Antworten
-
Nachtrag:
Ich bin nicht an diesen Aufbau der XMl-Datei gebunden. Wenn einen andere Struktur eine einfachere Lösung bietet, kann ich entsprechend umbauen.
Grüße
- Bearbeitet kleo-patra Montag, 29. Oktober 2018 08:06
-
Hier findest du die Beschreibung:
https://www.windowspro.de/script/xml-powershell-elemente-attribute-auslesen-textknoten-anzeigenStatt Server1....ServerN würde ich auch hier einfach nur "Server" als Id verwenden, dann kannst du wieder per Arrayindex zugreifen.
-
Hallo bfuerchau,
vielen Dank für Deine Antwort. Bei meiner Suche bin ich auch über diese Seite gestolpert. Leider habe ich dort nichts gefunden, was mir weiterhilft. (Oder ich habe es gefunden, aber leider nicht verstanden; das ist durchaus möglich.)
Anmerkung zu Deinem Vorschlag, auf die Server als Array zuzugreifen:
Ich habe hier nur einen exemplarischen Aufbau der Datei angegeben. Im echten Leben haben die Server richtige Namen (zum Beispiel DBServer1 und DBServer2 und SkriptServer1 und sowas.) Auf jeden Fall vielen Dank für die Anregung.
- Bearbeitet kleo-patra Montag, 29. Oktober 2018 10:05 Tippfehler
-
Zuerst erstellst du eine Variable vom Typ XML:
$xml = New-Object System.XML.XMLDocument
Dann lädst du dein Dokument:
$xml.Load("MyXml.xml")
Der Zugriff auf die Knoten erfolgt nun über die Namen direkt:
$xml.System.Umgebungen.Umgebung[0].Mandant[0].Server1
Du kannst das ganze auch interaktiv durchführen.
Wenn du nur die 1. Ebene ausgibst, werden nur diese ELemente angezeigt. Die angezeigten Namen kannstdu dann direkt verwenden.Hier ein weiteres Beispiel:
https://www.codeproject.com/Articles/61900/PowerShell-and-XML
-
Hallo,
so auf die schnell würde ich das wie folgt lösen:
[xml]$xml = Get-Content C:\Temp\xml.xml ($xml.System.Umgebungen.Umgebung | Where-Object {$_.Name -eq "Produktion"}).Mandant.Server1
gibt aber bestimmt eine eleganter Lösung.
lg
- Als Antwort vorgeschlagen Denniver ReiningMVP, Moderator Samstag, 3. November 2018 11:04
- Als Antwort markiert Denniver ReiningMVP, Moderator Dienstag, 6. November 2018 12:10
-
Vielen Dank für Eure Antworten.
Wenn ich das jetzt richtig verstehe, gibt es eine Lösung, so wie ich sie mir vorstelle, wohl einfach nicht.
Mein Workaround entspricht ungefähr der Lösung von Schlieng:
[xml]$i=gc -Path 'C:\tmp\Umgebungen.xml' $j=($i.System.Umgebungen.Umgebung|where{$_.name -eq 'Testanlage'}).Mandant|where{$_.Name -eq 'Innendienst'}
Wenn jemand noch eine weitere Idee hat, würde ich mich freuen, wenn er sie hier postet.
Vielen Dank und liebe Grüße
Sabine
-
Geht schon - mit XPath und Select-XML:
$TestAussen = select-xml $xmldoc -XPath "//System//Umgebungen//Umgebung[@Name='Testanlage']//Mandant[@Name='Aussendienst']"
Aber aufpassen, das ist komplett case sensitive. Es hat sich bewährt, Node- und Attributnamen komplett klein zu schreiben und nur Attributwerte bzw. Textinhalte bei Bedarf "richtig". Wenn Du alleine schon Attributinhalte case-insensitive suchen willst, mußt Du ne komplette Umwandlung in Klein- oder Großbuchstaben machen und erst dann suchen.
Und es hat sich auch bewährt, für einfaches Skripting auf Elemente wie <Server1>abc1</Server1> zu verzichten und stattdessen <server1 name="abc1"/> zu verwenden :)
Oder noch besser <server num="1" name="abc"/>. Node-Elemente möglichst generisch, differenzieren durch Attribute.
Greetings/Grüße, Martin - https://mvp.microsoft.com/en-us/PublicProfile/5000017 Mal ein gutes Buch über GPOs lesen? - http://www.amazon.de/Windows-Server-2012--8-Gruppenrichtlinien/dp/3866456956 Good or bad GPOs? My blog - http://evilgpo.blogspot.com And if IT bothers me? Coke bottle design refreshment - http://sdrv.ms/14t35cq
- Als Antwort vorgeschlagen Denniver ReiningMVP, Moderator Samstag, 3. November 2018 11:05
- Als Antwort markiert Denniver ReiningMVP, Moderator Dienstag, 6. November 2018 12:10
-
Wie immer führen viele Wege zum Ziel.
Noch mal zurück auf Anfang:
XML bietet dir nur eine Schema-Definition ähnlich eine SQL-Tabelle, mit dem Unterschied, dass man eine XML-Knoten-Hierarchie bilden kann.Alle XML-Namen "<Name Attr1="" Attr2="">....</Name>" sind wie Spaltennamen zu sehen.
Die Direktansprache funktioniert natürlich nur über die Knoten-/Attributnamen.Wenn man nach Inhalten sucht, kommst du halt um Suchfunktionen nicht herum.
Alternativ kannst du jedoch ebenso statt "<Mandant>" auch einen Knoten "<Innendienst>" definieren, der dann direkt ansprechbar ist. Das macht die XML-Verarbeitung aber ggf. unflexibel.
<?xml version="1.0" encoding="utf-8"?> <System> <Umgebungen> <Testanlage> <Aussendienst> <Server Name="xyz1" /> <Server Name="xyz2" /> </Aussendienst> <Innendienst> <Server Name="xyz3" /> <Server Name="xyz4" /> </Innendienst> </Umgebung> <Produktion> <Aussendienst> <Server Name="xyz5" /> <Server Name="xyz6" /> </Aussendienst> <Innendienst> <Server Name="xyz7" /> <Server Name="xyz8" /> </Innendienst> </Produktion </Umgebungen> </System>
Somit hast du dann wieder die Ansprache
$xml.Umgebungen.Testanlage.Aussendienst.Server
Wobei Server dann eben als Array ansprechbar sind.
$xml.Umgebungen.Testanlage.Aussendienst.Server[0].Attributes["Name"]$xml.Umgebungen.Testanlage.Aussendienst.Server.Count = Anzahl Knoten.
Das Ganze geht natürlich auch variabel, da sichdie Knotennamen auchauslesen lassen:$xml.Umgebungen.Count = Anzahl Knoten
$xml.Umgebungen[0].Name = Testanlage
$xml.Umgebungen[1].Name = Produktion$Name = $xml.Umgebungen[0].Name
$xml.Umgebungen[$Name].Innendienstusw. usf.
Noch ein Unterschied:
select-xml liest ein Dokument ein, durchsucht es, liefert das Ergebnis und verwirft das Dokument dann wieder.
Jedes neue select-xml wiederholt den gesamten Vorgang.
select-xml kann man dann verwenden, wenn man nur 1 Mal auf das Dokument zugreifen will.Liest man das Dokument aber direkt ein, kann man es mittels "$xml.SelectNodes" oder "$xml.SelectSingleNode" immer wieder durchsuchen.
- Als Antwort vorgeschlagen Denniver ReiningMVP, Moderator Samstag, 3. November 2018 11:05
- Als Antwort markiert Denniver ReiningMVP, Moderator Dienstag, 6. November 2018 12:10