2012-05-20 25 views
5

Aby uzyskać konkretny węzeł DOM osadzony w bieżącym dokumencie WWW z instancji TChromium, używając jej identyfikatora, należy użyć ICefDomDocument.getElementById(). Ale jak znaleźć elementy według atrybutu NAME? JavaScript ma metodę document.getElementsByName() i TWebBrowser (która owija IE) ma podobne wywołanie, ale nie mogę wymyślić, jak to zrobić z TChromium. Potrzebuję znaleźć elementy DOM, które mają atrybuty NAME, ale nie mają atrybutów ID. Przeszukałem jednostkę ceflib i nie widziałem niczego, co mogłoby to zrobić.Jak zdobyć elementy według nazwy w Delphi Chromium Embedded?

Pytanie boczne. Jeśli ktoś ma link do strony z "recepturami" w stylu TChromium, mógłbym go użyć.

AKTUALIZACJA: Czekając na odpowiedź, wymyślam następujący kod do wykonywania getElementsbyName(). Chciałbym czegoś szybszego niż skanowanie całego drzewa DOM. Jeśli widzisz coś złego w kodzie daj mi znać:

type 
    TDynamicCefDomNodeArray = array of ICefDomNode; 


// Given a Chromium document interface reference and a NAME attribute to search for, 
// return an array of all DOM nodes whose NAME attribute matches the desired. 
function getElementsByName(ADocument: ICefDomDocument; theName: string): TDynamicCefDomNodeArray; 

    // Get all the elements with a particular NAME attribute value and return 
    // an array of them. 
    procedure getElementsByName1(intfParentNode: ICefDomNode; theName: string; var aryResults: TDynamicCefDomNodeArray); 
    var 
     oldLen: integer; 
     intfChildNode: ICefDomNode; 
     theNameAttr: string; 
    begin 
     Result := nil; 
     intfChildNode := nil; 

     if Assigned(intfParentNode) then 
     begin 
      // Attributes are case insensitive. 
      theNameAttr := intfParentNode.GetElementAttribute('name'); 

      if AnsiSameText(theNameAttr, theName) then 
      begin 
       // Name attribute match. Add it to the results array. 
       oldLen := Length(aryResults); 
       SetLength(aryResults, oldLen + 1); 
       aryResults[oldLen] := intfParentNode; 
      end; // if AnsiSameText(intfParentNode.Name, theName) then 

      // Does the parent node have children? 
      if intfParentNode.HasChildren then 
      begin 
       intfChildNode := intfParentNode.FirstChild; 

       // Scan them. 
       while Assigned(intfChildNode) do 
       begin 
        getElementsByName1(intfChildNode, theName, aryResults); 

        if Assigned(intfChildNode) then 
         intfChildNode := intfChildNode.NextSibling; 
       end; 
      end; // if intfParentNode.HasChildren then 
     end; // if Assigned(intfParentNode) then 
    end; 

    // --------------------------------------------------------------- 

var 
    intfCefDomNode: ICefDomNode; 
begin 
    intfCefDomNode := nil; 
    Result := nil; 

    if Assigned(ADocument) then 
    begin 
     // Check the header. 
     intfCefDomNode := ADocument.Document; 

     if Assigned(intfCefDomNode) then 
     begin 
      // Check the parent. 
      getElementsByName1(intfCefDomNode, theName, Result); 
     end; // if Assigned(intfCefDomNode) then 
    end; // if Assigned(ADocoument) then 
end; 

// --------------------------------------------------------------- 
+0

Nie sądzę, że jest mądry, aby łączyć ze sobą 10-letnią technologię ze stanem rzeczy sztuki i oczekiwać, że aby stać się znaleźć i stabilne rozwiązanie. W tym konkretnym przypadku TChromium nie obsługuje Delph 6. http://code.google.com/p/delphichromiumembedded/ –

+0

@Jeroen, ['TChromium'] (http://code.google.com/p/delphichromiumembedded /) nie obsługuje Delphi 6 (nie ma dla niego pakietu), ale nie oznacza to, że nie może tam pracować. Mam Delphi 2009, który jest również nieobsługiwany, ale patrząc na źródło, nie ma nic, co mogłoby powstrzymać jego użycie ;-) – TLama

+0

@TLama, jeśli mój umysł dobrze mi służy, Delphi 7 wprowadziła sporo poprawek związanych z zawijaniem rzeczy COM. To może być powód, by nie wspierać Delphi 6. Poleciłbym Robertowi zweryfikować to założenie z zespołem TChromium. –

Odpowiedz

3

Nie ma funkcji JavaScript jak na getElementsByName lub MSHTML getElementsByName zbudowany w Chromium Embedded ani owijki Delphi w tym czasie. Możesz rozwiązać ten problem tylko przez iterację wszystkich elementów DOM, np. tworząc własne klasy DOM odwiedzających tak:

Uwaga procedura VisitDom jest asynchroniczne, więc powraca natychmiast (właściwie zanim użytkownik DOM zakończy visit) i współpracuje z migawkę DOM w momencie realizowanej .

type 
    TElementNameVisitor = class(TCefDomVisitorOwn) 
    private 
    FName: string; 
    protected 
    procedure visit(const document: ICefDomDocument); override; 
    public 
    constructor Create(const AName: string); reintroduce; 
    end; 

procedure ProcessElementsByName(const AFrame: ICefFrame; const AName: string); 
var 
    Visitor: TElementNameVisitor; 
begin 
    if Assigned(AFrame) then 
    begin 
    Visitor := TElementNameVisitor.Create(AName); 
    AFrame.VisitDom(Visitor); 
    end; 
end; 

procedure TForm1.Button1Click(Sender: TObject); 
begin 
    ProcessElementsByName(Chromium1.Browser.MainFrame, 'NameAttributeValue'); 
end; 

{ TDOMElementNameVisitor } 

constructor TElementNameVisitor.Create(const AName: string); 
begin 
    inherited Create; 
    FName := AName; 
end; 

procedure TElementNameVisitor.visit(const document: ICefDomDocument); 

    procedure ProcessNode(ANode: ICefDomNode); 
    var 
    Node: ICefDomNode; 
    begin 
    if Assigned(ANode) then 
    begin 
     Node := ANode.FirstChild; 
     while Assigned(Node) do 
     begin 
     if Node.GetElementAttribute('name') = FName then 
     begin 
      // do what you need with the Node here 
      ShowMessage(Node.GetElementAttribute('value')); 
     end; 
     ProcessNode(Node); 
     Node := Node.NextSibling; 
     end; 
    end; 
    end; 

begin 
    ProcessNode(document.Body); 
end; 
+1

re: ponowne wymyślanie koła. Nie celowo, po prostu wykorzystałem to, co znalazłem podczas badania przy użyciu Chromium z Delphi (zobacz moją odpowiedź na twój komentarz do głównego postu). –

+0

Więc biorę to, że wizyta wywołująca z potomkiem TCefDomVisitorOwn implementuje wzór Odwiedzającego? Innymi słowy, CEF zastosuje ten wzorzec do wszystkich węzłów w DOM, obsługując rekurencyjne zejście przez drzewo węzłów? To bardzo fajne, jeśli tak, ale chcę być absolutnie pewny, więc proszę o potwierdzenie. –

+0

Nie, iteracja, którą musisz zrobić jeszcze przez własną. Różnica w korzystaniu z metody 'VisitDom' polega na tym, że tworzy kopię (migawkę) bieżącego stanu DOM. W moim przykładzie "TElementNameVisitor.visit" działa z kopią dokumentu, a nie z samym dokumentem (który można zmienić w czasie iteracji). Nie wiem, czy to jest szybsze, to po prostu bezpieczniejsze. – TLama

Powiązane problemy