h41msh1c0r
Goto Top

XML mit Powershell auslesen und TreeView füllen

Hi@Alle XML Powershell Profi's,

<Data>
 <Hersteller ID="Adobe">  
  <Program>
    <Name>Adobe Reader</Name>
    <Version>11</Version>
  </Program>
  <Program>
   <Name>Adobe Professional</Name>
   <Version>7</Version>
  </Program>
 </Hersteller>
 <Hersteller ID="Microsoft">  
  <Program>
    <Name>Visual Studio</Name>
    <Version>11</Version>
  </Program>
  <Program>
   <Name>Office</Name>
   <Version>2013</Version>
  </Program>
 </Hersteller>
</Data>

Zum Test will ich den Inhalt meines Beispiel XML Files in einer TreeView darstellen.

Inhalt des Files in das Variable(Objekt?) $xml laden.
$xml = [XML] (Get-Content -Path c:\temp\Beispiel.xml)

<Hersteller>
  <Program>
    <Name>Adobe Reader</Name>
    <Version>11</Version>
  </Program>
<Hersteller>

Wenn ich den obrigen Block ohne ID="Adobe" versehe bekomme ich die Variablen ausgelesen.

$Collection =$xml.DB.Data.Hersteller.Program

$ProgramName = $Collection | %($_.Name)
$ProgramVersion = $Collection | %($_.Version)


Wenn ich nun das TreeView füllen will bekomme ich das mit folgendem hin:

$treeView1.Nodes.Add($Hersteller)
$treeView1.Nodes.Nodes.Add($ProgramName)
$treeView1.Nodes.Nodes.Nodes.Add($ProgramVersion)

Allerdings scheiters immo noch wenn ich dem TAG Hersteller eine ID mitgebe. Die Idee mit der ID ist das ich im Block <Program> nicht noch den Herstellernamen mitschleppen muss sondern das eine Ebene höher einmal abgefackelt wird.

Das Füllen muss ich auch noch dynamisch hinbekommen, da wird dann eine foreach Schleife herhalten müssen, aber soweit bin ich noch nicht

Gruß

Content-Key: 242481

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

Ausgedruckt am: 28.03.2024 um 09:03 Uhr

Mitglied: colinardo
Lösung colinardo 02.07.2014 aktualisiert um 14:30:00 Uhr
Goto Top
Moin,
 $xml = new-object XML
 $xml.Load("c:\temp\Beispiel.xml")  
 $treeView1.Nodes.Clear()
 $rootNode = $treeView1.Nodes.Add($xml.ChildNodes.Name)
 $xml.Data.Hersteller | %{$tn = $rootNode.Nodes.Add($_.ID); $_.Program | %{$tn.Nodes.Add($_.Name+" "+$_.Version)}}  
Dies passt jetzt auf die Beispiel-XML-Datei.

Wenn man eine XML-Datei universell parsen möchte, also alle Nodes egal wie tief verschachtelt, kann man dies mit einem rekursiven Aufruf machen:
Beispiel
function parseXML([System.Xml.XmlNode]$node,[System.Windows.Forms.TreeNode]$treenode){
    $node.Childnodes | %{$tn = $treenode.Nodes.Add($_.Name); parseXML $_ $tn}
}
Dieser Funktion muss man dann initial einen XML-Knoten übergeben ab dem das XML-File geparst wird und einen Knoten im Treeview-Objekt ab dem man das XML-File darstellen möchte.

back-to-topBeispiel: Universeller XML to TreeView-Parser
# Form Function
function GenerateForm {

#region Import the Assemblies
[reflection.assembly]::loadwithpartialname("System.Windows.Forms") | Out-Null  
[reflection.assembly]::loadwithpartialname("System.Drawing") | Out-Null  
#endregion

#region Generated Form Objects
$form1 = New-Object System.Windows.Forms.Form
$treeView1 = New-Object System.Windows.Forms.TreeView
$btnLoadXML = New-Object System.Windows.Forms.Button
$openFileDialog1 = New-Object System.Windows.Forms.OpenFileDialog
$InitialFormWindowState = New-Object System.Windows.Forms.FormWindowState
#endregion Generated Form Objects

#----------------------------------------------
# Event Script Blocks
#----------------------------------------------
$handler_btnLoadXML_Click= 
{
    if ($openFileDialog1.ShowDialog()){
        $treeView1.Nodes.Clear()
        $xml = new-object XML
        $xml.Load($openFileDialog1.FileName)
        $rootNode = $treeView1.Nodes.Add($xml.ChildNodes.Name)
        parseXML $xml.DocumentElement $rootNode
    }

}

function parseXML([System.Xml.XmlNode]$node,[System.Windows.Forms.TreeNode]$treenode){
    $node.Childnodes | %{$tn = $treenode.Nodes.Add($_.Name); parseXML $_ $tn}
}

$OnLoadForm_StateCorrection=
{#Correct the initial state of the form to prevent the .Net maximized form issue
	$form1.WindowState = $InitialFormWindowState
}

#----------------------------------------------
#region Generated Form Code
$System_Drawing_Size = New-Object System.Drawing.Size
$System_Drawing_Size.Height = 217
$System_Drawing_Size.Width = 222
$form1.ClientSize = $System_Drawing_Size
$form1.DataBindings.DefaultDataSourceUpdateMode = 0
$form1.Name = "form1"  
$form1.Text = "XML to TreeView"  

$treeView1.Anchor = 15
$treeView1.DataBindings.DefaultDataSourceUpdateMode = 0
$System_Drawing_Point = New-Object System.Drawing.Point
$System_Drawing_Point.X = 12
$System_Drawing_Point.Y = 41
$treeView1.Location = $System_Drawing_Point
$treeView1.Name = "treeView1"  
$System_Drawing_Size = New-Object System.Drawing.Size
$System_Drawing_Size.Height = 164
$System_Drawing_Size.Width = 198
$treeView1.Size = $System_Drawing_Size
$treeView1.TabIndex = 1

$form1.Controls.Add($treeView1)

$btnLoadXML.Anchor = 13

$btnLoadXML.DataBindings.DefaultDataSourceUpdateMode = 0

$System_Drawing_Point = New-Object System.Drawing.Point
$System_Drawing_Point.X = 12
$System_Drawing_Point.Y = 12
$btnLoadXML.Location = $System_Drawing_Point
$btnLoadXML.Name = "btnLoadXML"  
$System_Drawing_Size = New-Object System.Drawing.Size
$System_Drawing_Size.Height = 23
$System_Drawing_Size.Width = 198
$btnLoadXML.Size = $System_Drawing_Size
$btnLoadXML.TabIndex = 0
$btnLoadXML.Text = "XML-Datei laden"  
$btnLoadXML.UseVisualStyleBackColor = $True
$btnLoadXML.add_Click($handler_btnLoadXML_Click)

$form1.Controls.Add($btnLoadXML)

$openFileDialog1.FileName = "fd"  
$openFileDialog1.Filter = "XML-Dateien|*.xml"  
$openFileDialog1.ShowHelp = $True

#endregion Generated Form Code

#Save the initial state of the form
$InitialFormWindowState = $form1.WindowState
#Init the OnLoad event to correct the initial state of the form
$form1.add_Load($OnLoadForm_StateCorrection)
#Show the Form
$form1.ShowDialog()| Out-Null

} #End Function

GenerateForm
Grüße Uwe
Mitglied: H41mSh1C0R
H41mSh1C0R 02.07.2014 um 13:33:53 Uhr
Goto Top
Hallo Uwe,

schonmal danke, leider will das noch nicht so:

ERROR: [ : Unable to index into an object of type System.Xml.XmlChildNodes.
ERROR:
MainForm.pff (177): ERROR: At Line: 177 char: 51
ERROR: +      $rootNode = $treeView1.Nodes.Add($xml.ChildNodes[ <<<< 0].Name)
ERROR:     + CategoryInfo          : InvalidOperation: (0:Int32) , RuntimeException
ERROR:     + FullyQualifiedErrorId : CannotIndex
ERROR:
ERROR: Add : You cannot call a method on a null-valued expression.
ERROR:
MainForm.pff (178): ERROR: At Line: 178 char: 52
ERROR: +      $xml.Data.Hersteller | %{$tn = $rootNode.Nodes.Add <<<< ($_.ID); $_.Program | %{$tn.Nodes.Add($_.Name+" "+$_.Version)}}  
ERROR:     + CategoryInfo          : InvalidOperation: (Add:String) , RuntimeException
ERROR:     + FullyQualifiedErrorId : InvokeMethodOnNull
ERROR:
ERROR: Add : You cannot call a method on a null-valued expression.
ERROR:
MainForm.pff (178): ERROR: At Line: 178 char: 89
ERROR: +      $xml.Data.Hersteller | %{$tn = $rootNode.Nodes.Add($_.ID); $_.Program | %{$tn.Nodes.Add <<<< ($_.Name+" "+$_.Version)}}  
ERROR:     + CategoryInfo          : InvalidOperation: (Add:String) , RuntimeException
ERROR:     + FullyQualifiedErrorId : InvokeMethodOnNull
ERROR:

Wieso benutzt du im hinteren Teil $_. und vorn direk $?

Gruß
Mitglied: colinardo
colinardo 02.07.2014 aktualisiert um 13:36:46 Uhr
Goto Top
Zitat von @H41mSh1C0R:
schonmal danke, leider will das noch nicht so:
geht hier einwandfrei mit deinem XML-Schnippsel:

DEMO:
#Generated Form Function
function GenerateForm {

#region Import the Assemblies
[reflection.assembly]::loadwithpartialname("System.Windows.Forms") | Out-Null  
[reflection.assembly]::loadwithpartialname("System.Drawing") | Out-Null  
#endregion

#region Generated Form Objects
$form1 = New-Object System.Windows.Forms.Form
$treeView1 = New-Object System.Windows.Forms.TreeView
$btnLoadXML = New-Object System.Windows.Forms.Button
$InitialFormWindowState = New-Object System.Windows.Forms.FormWindowState
#endregion Generated Form Objects

#----------------------------------------------
#Generated Event Script Blocks
#----------------------------------------------

$rawXML = @"  
<Data>
 <Hersteller ID="Adobe">  
  <Program>
    <Name>Adobe Reader</Name>
    <Version>11</Version>
  </Program>
  <Program>
   <Name>Adobe Professional</Name>
   <Version>7</Version>
  </Program>
 </Hersteller>
 <Hersteller ID="Microsoft">  
  <Program>
    <Name>Visual Studio</Name>
    <Version>11</Version>
  </Program>
  <Program>
   <Name>Office</Name>
   <Version>2013</Version>
  </Program>
 </Hersteller>
</Data>
"@  

$handler_btnLoadXML_Click= 
{
    $treeView1.Nodes.Clear()
    $xml = new-object XML
    $xml.LoadXml($rawXML)
    $rootNode = $treeView1.Nodes.Add($xml.ChildNodes.Name)
    $xml.Data.Hersteller | %{$tn = $rootNode.Nodes.Add($_.ID); $_.Program | %{$tn.Nodes.Add($_.Name+" "+$_.Version)}}  

}


$OnLoadForm_StateCorrection=
{#Correct the initial state of the form to prevent the .Net maximized form issue
	$form1.WindowState = $InitialFormWindowState
}

#----------------------------------------------
#region Generated Form Code
$System_Drawing_Size = New-Object System.Drawing.Size
$System_Drawing_Size.Height = 217
$System_Drawing_Size.Width = 222
$form1.ClientSize = $System_Drawing_Size
$form1.DataBindings.DefaultDataSourceUpdateMode = 0
$form1.Name = "form1"  
$form1.Text = "XML to TreeView"  

$treeView1.Anchor = 15
$treeView1.DataBindings.DefaultDataSourceUpdateMode = 0
$System_Drawing_Point = New-Object System.Drawing.Point
$System_Drawing_Point.X = 12
$System_Drawing_Point.Y = 41
$treeView1.Location = $System_Drawing_Point
$treeView1.Name = "treeView1"  
$System_Drawing_Size = New-Object System.Drawing.Size
$System_Drawing_Size.Height = 164
$System_Drawing_Size.Width = 198
$treeView1.Size = $System_Drawing_Size
$treeView1.TabIndex = 1

$form1.Controls.Add($treeView1)

$btnLoadXML.Anchor = 13

$btnLoadXML.DataBindings.DefaultDataSourceUpdateMode = 0

$System_Drawing_Point = New-Object System.Drawing.Point
$System_Drawing_Point.X = 12
$System_Drawing_Point.Y = 12
$btnLoadXML.Location = $System_Drawing_Point
$btnLoadXML.Name = "btnLoadXML"  
$System_Drawing_Size = New-Object System.Drawing.Size
$System_Drawing_Size.Height = 23
$System_Drawing_Size.Width = 198
$btnLoadXML.Size = $System_Drawing_Size
$btnLoadXML.TabIndex = 0
$btnLoadXML.Text = "XML parsen"  
$btnLoadXML.UseVisualStyleBackColor = $True
$btnLoadXML.add_Click($handler_btnLoadXML_Click)
$form1.Controls.Add($btnLoadXML)

#Save the initial state of the form
$InitialFormWindowState = $form1.WindowState
#Init the OnLoad event to correct the initial state of the form
$form1.add_Load($OnLoadForm_StateCorrection)
#Show the Form
$form1.ShowDialog()| Out-Null

} #End Function

#Call the Function
GenerateForm
Mitglied: H41mSh1C0R
H41mSh1C0R 02.07.2014 um 13:53:06 Uhr
Goto Top
Hab jetzt mal deine Demo copy pasted und bekomme den gleichen Fehler. hmmmm
Mitglied: colinardo
colinardo 02.07.2014 aktualisiert um 13:54:59 Uhr
Goto Top
Powershell Updaten !! Mind. PS3.0

Geht hier einwandfrei...
Mitglied: H41mSh1C0R
H41mSh1C0R 02.07.2014 um 14:11:09 Uhr
Goto Top
Ahhh danke, geht. =)

Die PS ist bereits auf der 4, aber das Powershell Studio was ich hier zur Verfügung habe kann maximal PS2. *gg*
Der PS3 Support ist in der Version auch noch deaktiviert.

Also solange immer zwischen ISE und Studio hin und her.

Nochmals danke Uwe.