0

i am trying to build myself the XPath for an element clicked (e.g.) on a website inside of a TWebBrowser. if you know some available functions or an other way please give me a hint.

procedure TForm1.Button2Click(Sender: TObject);
var
  Elem: IHTMLElement;
  ss: string;
  ii: Integer;
 function GetElemOrder(e: IHTMLElement): integer;
  var
    jj: Integer;
    ee: IHTMLElement;
    Coll: IHTMLElementCollection;
  begin
    //get all children of the elem parent - the elem is a child itself
    Coll := e.parentElement.children as IHTMLElementCollection;
    //filter the tags to minimize the list (only the same tags as the elem)
    Coll := Coll.tags(e.tagName) as IHTMLElementCollection;
    for jj := 0 to Coll.length - 1 do begin
      inc(Result);
      ee := Coll.item(jj, EmptyParam) as IHTMLElement;
      //go through the list and check if the elem was found
      if (e = ee) then  // <<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<< this doesn't work
        //return the actual count
        Exit;
    end;
    Result := 0; // result 0 means always an error, as the elem wasn't found in the collection
  end;

begin
  //get element obj
  Elem := GetElementById(wb.Document, 'input_username') as IHTMLElement;
  if Assigned(Elem) then
    //build the xpath until reach the root
    while elem.parentElement <> nil do begin
      // get the order of the elem in the list of children e.g. 3rd DIV from 5 DIVs
      ii := GetElemOrder(Elem);
      ss := '/' + Elem.tagName + '[' + ii.ToString + ']' + ss;
      //go to the next level
      Elem := Elem.parentElement;
    end;
end;

it works so far but i have a problem to compare 2 IHTMLElements. What am I doing wrong?

ramses
  • 49
  • 1
  • 11
  • 1
    `GetElemOrder()` is not initializing `Result` before trying to `Inc()` it. `Result` is not initialized to 0 automatically, you have to do that explicitly. See [What is the default value of 'Result' in Delphi?](https://stackoverflow.com/questions/5336863/). In this case, consider using `Exit(jj + 1);` instead, per the [documentation](http://docwiki.embarcadero.com/Libraries/en/System.Exit): "*Beginning with Delphi 2009, `Exit` can take a parameter specifying a result. The parameter must be of the same type as the result of the function.*" – Remy Lebeau Oct 08 '20 at 18:12
  • 2
    The correct way to test if two COM interface pointers refer to the same object in memory is to cast them to `IUnknown` before comparing them, ie `if (e as IUnknown) = (ee as IUnknown)`. See [Is there a way to tell whether two COM interface references point at the same instance?](https://stackoverflow.com/questions/323289/) – Remy Lebeau Oct 08 '20 at 18:14
  • @RemyLebeau many thanks! it works now as expected! initializing of 'result' will be done, don't know why here is absent. Great pointing to documentation! – ramses Oct 08 '20 at 18:29
  • If you use `Exit(...);` instead of `Exit;`, then you don't need to initialize `Result` at all, let alone `Inc()` it on each loop iteration. `function GetElemOrder(e: IHTMLElement): integer; ... begin ... for jj := 0 to Coll.length - 1 do begin ... if (...) Exit(jj+1); ... end; ... Exit(0); end;` – Remy Lebeau Oct 08 '20 at 18:33

0 Answers0