URIs in einen Treeview laden

Heute hat mich ein Kollege angesprochen und gefragt wie man ein Array aus URIs in einen Treeview laden kann, d.h. die hierarchische Struktur die in einer URI vorherrscht und durch die Slashes (/) symbolisiert wird soll in eine echte hierarchische Struktur im Treeview aufgelöst werden. Also aus dem hier:

_myURIs[0] = new Uri(http://www.pentagon.org/home); 
_myURIs[1] = new Uri(http://www.pentagon.org/secretStuff1); 
_myURIs[2] = new Uri(http://www.pentagon.org/secretStuff1/TopSecret); 
_myURIs[3] = new Uri(http://www.pentagon.org/secretStuff2/Classified); 
_myURIs[4] = new Uri(http://www.pentagon.org/secretStuff3); 
_myURIs[5] = newUri("http://www.pentagon.org/secretStuff2/DontTouch/Really/IMeanIt/Seriously");_myURIs[6] = new Uri("http://www.pentagon.org/");

Soll das hier werden:

062514_1915_URIsineinen1

 

Wenn man das Ganze als rekursive Funktion angeht ist es eigentlich nicht so schwierig und recht elegant in ein paar Zeilen Code hingeschrieben. Zunächst brauchen wir eine übergeordnete Funktion die die Root-Knoten behandelt und dann die Rekursion einleitet. So eine Funktion kann wie folgt aussehen:

foreach (Uri _curUri in _myURIs) 
{
  if (treeView1.Nodes.Find(_curUri.Host, false).Length == 0) 
    treeView1.Nodes.Add(_curUri.Host, _curUri.Host);
  // Wir wollen keine Slashes     
  fillUriInTree(_curUri.Segments.Where(w => w != "/").ToArray(),
       treeView1.Nodes.Find(_curUri.Host, false)[0]); 
}

Die If-Abfrage prüft, ob es den Host bereits als Root-Knoten gibt. Ist das nicht der Fall, so wird der Host als Root-Knoten angelegt. Das ist wichtig, damit der folgende Code diesen Knoten auch finden kann. Wenn es den Knoten schon gibt umso besser, dann muss nichts gemacht werden und der Knoten wird automatisch gefunden. In der Methode Nodes.Find geben wir als zweiten Parameter false an, da nicht in untergeordneten Knoten gesucht werden soll.

In der zweiten Zeile Code rufen wir unsere rekursive Füllfunktion auf die zunächst die über Uri.Segments in ein String-Array zerlegte URI (ohne Host) bekommen soll. Da Uri.Segments im Ergebnis-Array auch die Slashes (/) als eigene Elemente mitliefert (die wir aber im Tree nicht wollen) werden diese über eine LINQ-Abfrage rausgefiltert.

Kommen wir nun zur rekursiven Funktion. Die sieht wie folgt aus:

private void fillUriInTree (string[] pUriSegments, TreeNode pCurrentNode) 
{ 
  if (pUriSegments.Length > 0) 
  { 
    // FGE: gibt es den Knoten auf der aktuellen Ebene?     
    if (pCurrentNode.Nodes.Find(pUriSegments[0].Replace("/",""), 
        false).Length != 0)
    { 
      // FGE: Gibts schon -> entfernen und eine Ebene tiefer weitermachen
      fillUriInTree(pUriSegments.Where(w => w != pUriSegments[0]).ToArray(), 
          pCurrentNode.Nodes.Find(pUriSegments[0].Replace("/", ""), false)​
          [0]); 
    } 
    else     
    { 
     // FGE: gibt es noch nicht -> Anlegen und eine Ebene tiefer weitermachen     
     fillUriInTree(pUriSegments.Where(w => w != pUriSegments[0]).ToArray(), 
        pCurrentNode.Nodes.Add(pUriSegments[0].Replace("/", ""), 
        pUriSegments[0].Replace("/", ""))); 
    } 
  } 
}

Die rekursive Funktion bekommt die beiden Parameter pUriSegments und pCurrentNode übergeben. In pUriSegments werden die verbleibenden, noch nicht in den Treeview eingefügten Werte übergeben und in pCurrentNode befindet sich der aktuelle Treeview Knoten. Bei der ersten Rekursion ist das der komplette URI (ohne Host) und der Host-Knoten. Das wichtigste bei einer Rekursion ist die Abbruch-Bedingung, die als aller erstes geprüft wird. Die Funktion wird nur dann aufgerufen wenn sich noch Elemente im Array pUriSegments befinden. Ist das Array leer sind wir mit der Arbeit durch und die Funktion kann beendet werden. War das Array nicht leer wird überprüft ob es das aktuelle URI-Segment bereits als Knoten im Treeview gibt. Ist das der Fall, so wird über den LINQ Ausdruck einfach das erste (also nullte) Element des URI-Segment-Arrays entfernt und der gefundene Knoten im Treeview wird als neuer Ausgangsknoten für den erneuten Aufruf der Funktion verwendet. Gab es das URI-Segment im Treeview bisher nicht wird es in der Übergabe für den nächsten Rekursionsdurchgang erzeugt und gleichzeitig aus dem URI-Segment-Array gelöscht. Da am Ende der URI-Segmente immer noch der Slash (/) ist, wird dieser über das Replace gelöscht.

Schreibe einen Kommentar

Deine E-Mail-Adresse wird nicht veröffentlicht. Erforderliche Felder sind mit * markiert.

%d Bloggern gefällt das: