AGB  ·  Datenschutz  ·  Impressum  







Anmelden
Nützliche Links
Registrieren
Zurück Delphi-PRAXiS Programmierung allgemein Programmieren allgemein XML Delphi IUnknown / XML-Link im TreeView
Thema durchsuchen
Ansicht
Themen-Optionen

IUnknown / XML-Link im TreeView

Ein Thema von StTüff · begonnen am 22. Aug 2007 · letzter Beitrag vom 23. Aug 2007
Antwort Antwort
StTüff

Registriert seit: 3. Dez 2002
132 Beiträge
 
Delphi 2006 Enterprise
 
#1

IUnknown / XML-Link im TreeView

  Alt 22. Aug 2007, 13:17
Hallo!

Ich habe vor einiger Zeit mit Eurer Hilfe (vor allem marabu hat mir sehr geholfen) eine Funktion ausgeknobelt, mit der man durch vergleichen der Zeiger herausfinden kann, welcher XML-Knoten zum entsprechenden Treeviewknoten gehört.
Siehe auch:
http://www.delphipraxis.net/internal...220&highlight=

Die Funktion sieht wie folgt aus:
Delphi-Quellcode:
function FindTreeNodeXML(LinkedXMLNode:IXMLDOMNode):TTreeNode;
var
  cnt:integer;
  u_LinkedNode, u_chekNode : IUnknown;
begin
  //Durch alle Knoten laufen
  for cnt:= 0 to form1.TrView_Struktur.Items.Count-1 do
  begin
    u_chekNode := PNodeState(form1.TrView_Struktur.
                  Items[cnt].Data).XMLNode as IUnknown;
    u_LinkedNode := LinkedXMLNode as IUnknown;
    if u_chekNode = u_LinkedNode then
    begin
      result:=form1.TrView_Struktur.Items[cnt];
      exit;
    end;
  end;
  result:=nil;
end;
Das funktioniert soweit wunderbar. Leider kommte es aber sehr selten dazu, dass die Zeiger nicht mehr zueinander passen, obwohl (nachweislich) sowohl der XML-, als auch der Treeviewknoten noch vorhanden ist. Wenn die Baumansicht aktualisiert bzw. neu aufgebaut wird, stimmen die Zeiger wieder.

Da ich zwar beim Vergleich das Elemtarinterface (IUnknown) verwende, aber zu den TreeView-Knoten einfach den Zeiger auf den XML-Knoten, ist meine Vermutung, dass dieses Problem durch eine Aktion des Betriebssystems hervorgerufen wird, die dafür sorgt, dass die Zeiger nicht mehr zueinander passen?

Ist meine Theorie richtig?
Wenn ich schonn beim Speichern des Zeigers im Treeview IUnknown verwenden würde, würde das das Problem lösen?

Das Problem tritt sehr selten (meist nach langer Wartezeit) auf und ist dementsprechend schwer zu reproduzieren. Wenn es aber auftritt, so sind alle Zeiger, die im Treeview abgelegt wurden, betroffen.

Hat jemand eine Idee hierzu? Was kann die Ursache sein?

Gruß,

StTüff
  Mit Zitat antworten Zitat
shmia

Registriert seit: 2. Mär 2004
5.508 Beiträge
 
Delphi 5 Professional
 
#2

Re: IUnknown / XML-Link im TreeView

  Alt 22. Aug 2007, 13:31
Du darfst eigentlich nicht direkt die Interfacepointer vergleichen, sondern den XPath.
Ein XMLNode hat ja einen vollständigen Pfad (z.B.: /rss/chanel/item[3]/title)
Wenn zwei Nodes den gleichen Pfad haben, dann sind sie gleich.
Andreas
  Mit Zitat antworten Zitat
StTüff

Registriert seit: 3. Dez 2002
132 Beiträge
 
Delphi 2006 Enterprise
 
#3

Re: IUnknown / XML-Link im TreeView

  Alt 22. Aug 2007, 13:48
Hallo Shmia!

Ich glaub das ist ein Missverständnis: Ich vergleiche keine 2 XML-Knoten miteinander.

Vielleicht noch mal kurz der Hintergrund:
Ich lese eine XML-Datei ein und stelle den Inhalt in einem Treeview dar. Damit ich später (beim Bearbeiten der Daten im TreeView) direkt auf die zugehörigen XML-Knoten zugreifen kann, lege ich beim Aufbau des Treeviews zu jedem TreeNode einen Zeiger auf den XML-Knoten ab.
Das funktioniert sehr gut.
Nun gibt es aber auch den ungedrehten Fall: Ich habe einen XML-Knoten und suche den zugehörigen Eintrag im TreeView. Auch das funktioniert mit der gezeigten Funktion sehr gut.

Leider kommt es aber in sehr seltenen Fällen zur Fehlfunktion. Es ist nicht durch eine User-Aktion reproduzierbar und scheint zufällig aufzutreten. Deshalb mein Verdacht richtung Betriebssystem (ist übrigens XP Prof.).

Gruß und vielen Dank für Deinen Beitrag,

StTüff
  Mit Zitat antworten Zitat
StTüff

Registriert seit: 3. Dez 2002
132 Beiträge
 
Delphi 2006 Enterprise
 
#4

Re: IUnknown / XML-Link im TreeView

  Alt 22. Aug 2007, 16:05
Hallo Shmia!

Ich glaube Du hattest es doch richtig verstanden. Bitte Entschuldige. Der Denkfehler liegt bei mir.
Ich vermute Du wolltest damit sagen, dass ich den XPath des tatsächlichen Knotens mit den Knoten, die (bzw. deren Zeiger) im Treeview hinterlegt sind vergleichen soll. Habe ich das jetzt richtig wiedergegeben?

Das ist theoretisch natürlich möglich. Da ich dann aber beim durchlaufen der Schleife für jeden Knoten im TreeView den XPath ermitteln müsste, ist das auch aufwendiger (zumindest rechenintensiver). Ich würde schon gerne bei der einfacheren Lösung bleiben, wenn sich nicht herausstellt, dass es hier grundsätzliche Dinge gibt, die dagegen sprechen.

Da es die meiste Zeit funktioniert hoffe ich den Grund noch zu finden, warum es manchmal ohne das Zutun des Anwenders schief geht. Ich hoffe zusätzlich darauf, dass sich das Problem dann einfach beheben lässt. Momentan kenne ich aber noch nicht ein mal den Grund, warum es in so seltenen Fällen daneben geht.

Gruß,

StTüff
  Mit Zitat antworten Zitat
shmia

Registriert seit: 2. Mär 2004
5.508 Beiträge
 
Delphi 5 Professional
 
#5

Re: IUnknown / XML-Link im TreeView

  Alt 22. Aug 2007, 17:47
Zitat von StTüff:
... dass ich den XPath des tatsächlichen Knotens mit den Knoten, die (bzw. deren Zeiger) im Treeview hinterlegt sind vergleichen soll. Habe ich das jetzt richtig wiedergegeben?
Ja, genau.
Zitat von StTüff:
Das ist theoretisch natürlich möglich. Da ich dann aber beim durchlaufen der Schleife für jeden Knoten im TreeView den XPath ermitteln müsste, ist das auch aufwendiger (zumindest rechenintensiver).
Das stimmt natürlich, zu mal der Pfad nicht von DOM geliefert wird.
Für MSXML könnte das so aussehen:
Delphi-Quellcode:
function GetFullNodePath(node:IXMLDOMNode):string;
var
   i : Integer;
   n : IXMLDOMNode;
begin
   if node.nodeType=NODE_DOCUMENT then
      Result := ''
   else if Assigned(node.parentNode) then
      // rekursiver Aufruf
      Result := GetFullNodePath(node.parentNode)+'/'+node.nodeName
   else
      Result := node.nodeName;

   // Anzahl der Vorgänger mit gleichem Namen feststellen
   n := node.previousSibling;
   i := 1;
   while Assigned(n) do
   begin
      if (n.nodeName = node.nodeName) and (n.nodeType = NODE_ELEMENT) then
         Inc(i);
      n := n.previousSibling;
   end;
   if i > 1 then
      Result := Result + '['+IntToStr(i)+']';
end;
Zitat von StTüff:
Ich würde schon gerne bei der einfacheren Lösung bleiben, wenn sich nicht herausstellt, dass es hier grundsätzliche Dinge gibt, die dagegen sprechen.
Da es die meiste Zeit funktioniert hoffe ich den Grund noch zu finden, warum es manchmal ohne das Zutun des Anwenders schief geht. Ich hoffe zusätzlich darauf, dass sich das Problem dann einfach beheben lässt. Momentan kenne ich aber noch nicht ein mal den Grund, warum es in so seltenen Fällen daneben geht.
Wenn ein Element oder Attribut verändert wird, gibt es evtl. 2 Instanzen des gleichen Knotens.
Ein Knoten kann auch mit .cloneNode() kopiert werden.
Auch wenn man über die Grenzen eines Threads (oder Appartment ?) geht, haben zwei Interfacepointer verschiedene Adressen.

Würde den sourcecode mal so ändern:
Delphi-Quellcode:
    u_chekNode := PNodeState(form1.TrView_Struktur.
                  Items[cnt].Data).XMLNode as IXMLDOMNode;
    if u_chekNode = LinkedXMLNode then
So spart man sich eine Interfaceumwandlung.
Vielleicht sollte man die 2. Umwandlung auch einsparen und einen Cast-Operator nehmen:
Delphi-Quellcode:
    u_chekNode := IXMLDOMNode(PNodeState(form1.TrView_Struktur.
                  Items[cnt].Data).XMLNode);
    if u_chekNode = LinkedXMLNode then
Manchmal ist es so, dass man verschiedene Interfacepointer bekommt, je nach dem
in welcher Reihenfolge man die Interface umgewandelt.
Das hat mit Aggregation und Containment zu tun und ist nicht einfach zu verstehen.
Andreas
  Mit Zitat antworten Zitat
marabu

Registriert seit: 6. Apr 2005
10.109 Beiträge
 
#6

Re: IUnknown / XML-Link im TreeView

  Alt 22. Aug 2007, 17:52
Hallo Stephan,

deine Funktion würde bei mir aus verschiedenen Gründen so aussehen:

Delphi-Quellcode:
function FindNode(nodes: TTreeNodes; data: Pointer): TTreeNode;
var
  i: Integer;
begin
  Result := nil;
  for i := 0 to Pred(nodes.Count) do
    if nodes[i].Data = data then
    begin
      Result := nodes[i];
      Break;
    end;
end;
Allerdings würde ich diese Funktion nicht benötigen, da ich so beim Suchen jedesmal im Mittel n/2 Knoten betrachten müsste. Ich würde für die Suche einen sortierbaren Container einführen, in welchem per binary search der TreeNode zu einem XmlNode gefunden werden kann. Die Signatur ändert sich dann geringfügig, indem dieser Container als erstes Argument an die Funktion FindNode() übergeben wird.

Zu deinem Bericht über die sporadisch und scheinbar unmotivierten Zeigerverluste fällt mir nur eines ein: Eventuell wurden die Schnittstellenzeiger zwischenzeitlich freigegeben und wieder neu erzeugt. Um das sicher auszuschließen, sollte vor dem Einfügen in den Container der Reference Count des Interface erhöht und beim Entfernen wieder erniedrigt werden. Fehler in deinem Code schließen wir mal aus...

Freundliche Grüße
  Mit Zitat antworten Zitat
StTüff

Registriert seit: 3. Dez 2002
132 Beiträge
 
Delphi 2006 Enterprise
 
#7

Re: IUnknown / XML-Link im TreeView

  Alt 23. Aug 2007, 07:02
Hallo Shmia!

Dein Vorschlag für den alternativen Code entspricht meiner ursprünglichen Funktion und funktioniert nicht, da sich diese Pointer tatsächlich ändern. Die Lösung war damals die Verwendung von IUnknown (siehe damaliger Thread).

In der XML-Struktur wird nichts verändert solange der Anwender nichts unternimmt. Da das Problem auch auftritt, wenn ich die Datei Lade und dann einfach für lange Zeit stehen lasse (die genaue Zeit konnte ich nicht ermitteln, scheint auch nicht konstant zu sein), kann ich ein Problem in meinem Code mit ziemlicher Sicherheit ausschließen (aber was ist schon sicher?).

Inzwischen habe ich mir eine kleine Debughilfe in das Programm eingebaut, die Informationen zu den Knoten ausgibt. Ich hoffe so das Problem besser eingrenzen zu können (Ist aber schwer, da es so selten auftritt).

Hallo Marabu!

Ehrlich gesagt überfordertst Du mich im Moment noch ein wenig (ich hoffe, dass ich weiter lerne...).
Ich möchte bezüglich der Suche momentan auch nichts optimieren, solange ich das Problem nicht genau kenne, zumal ich das durch die verwendung von Containern auch nicht löse, oder? Hört sich aber interesant an, hast Du mir einen Link zu einem ähnlichen Beispiel, bei dem ich das mal nachvollziehen kann?

Dein Vorschlag mit dem Referenzcount: Bezieht sich der nur auf die "Containerlösung", oder kann ich das auch verwenden? Wie erhöht man den Referncount manuell? Bei der Suche habe ich auf die Schnelle nicht viel gefunden.

Ich kann mir das ehrlich gesagt im Moment nicht richtig vorstellen, was da zu tun ist.

Zitat:
Eventuell wurden die Schnittstellenzeiger zwischenzeitlich freigegeben und wieder neu erzeugt.
Welche Gründe könnte das haben? Vermutlich werden die Schnittstellenzeiger doch freigegeben, wenn diese nicht mehr verwendet werden (also der Referenz Count = 0 ist?). Da aber beide Strukturen (XML und TreeView) vorhanden sind (der Treeview wird bei jedem Laden der XML-Datei aufgebaut), sollte auch der RefernzCount <> 0 sein.
Wenn das und die Aussage
Zitat:
Zwei Interface-Pointer zeigen auf dasselbe Objekt, wenn ihre IUnknown-Pointer identisch sind.
so stimmt, dann müsste es doch eigentlich (auch dauerhaft) gehen, oder?

Gruß,

Stüff
  Mit Zitat antworten Zitat
StTüff

Registriert seit: 3. Dez 2002
132 Beiträge
 
Delphi 2006 Enterprise
 
#8

Re: IUnknown / XML-Link im TreeView

  Alt 23. Aug 2007, 07:18
..... wartet mal ich glaube ich habe etwas gefunden ... muss das mal genauer anschauen .

Wenn meine Vermutung stimmt, dann liegt es doch wieder an meinem Code .

Melde mich wieder, wenn ich der Spur nachgegangen bin.

Gruß,

StTüff
  Mit Zitat antworten Zitat
StTüff

Registriert seit: 3. Dez 2002
132 Beiträge
 
Delphi 2006 Enterprise
 
#9

Re: IUnknown / XML-Link im TreeView

  Alt 23. Aug 2007, 07:36
Oh Gott ist das peinlich!

Zitat:
der Treeview wird bei jedem Laden der XML-Datei aufgebaut
Das hat mich auf die Idee gebracht. Es stimmt zwar schon, dass beim Laden der Treeview aufgebaut wird, es gibt aber noch eine XSL-Transformation, die ich übersehen hatte. Die Transformation ist nur dazu da, die Daten zu sortieren und wird auch nur dann ausgelöst, wenn die Daten nicht in der erwarteten Abfolge vorliegen. Da ich nach der Transformation den TreeView (bisher) nicht neu aufbaue, tritt an der Stelle das beschriebene Problem auf. Eigentlich ganz logisch, oder?

Liebes Windows: Ich nehme alle Verdächtigungen zurück.

Jetzt hätte ich Zeit, mich um eine optimierte Suche mit Containern zu kümmern.
Gibt es da Tutorials, etwas in der Codelibrary oder im WWW dazu? Oder: Lohnt es sich hierfür einen neuen Thread aufzumachen?

Gruß und vielen Dank an Euch!

StTüff
  Mit Zitat antworten Zitat
Antwort Antwort


Forumregeln

Es ist dir nicht erlaubt, neue Themen zu verfassen.
Es ist dir nicht erlaubt, auf Beiträge zu antworten.
Es ist dir nicht erlaubt, Anhänge hochzuladen.
Es ist dir nicht erlaubt, deine Beiträge zu bearbeiten.

BB-Code ist an.
Smileys sind an.
[IMG] Code ist an.
HTML-Code ist aus.
Trackbacks are an
Pingbacks are an
Refbacks are aus

Gehe zu:

Impressum · AGB · Datenschutz · Nach oben
Alle Zeitangaben in WEZ +1. Es ist jetzt 15:39 Uhr.
Powered by vBulletin® Copyright ©2000 - 2024, Jelsoft Enterprises Ltd.
LinkBacks Enabled by vBSEO © 2011, Crawlability, Inc.
Delphi-PRAXiS (c) 2002 - 2023 by Daniel R. Wolf, 2024 by Thomas Breitkreuz