2012-05-20 7 views
5

Um einen bestimmten DOM-Knoten aus einer TChromium-Instanz in das aktuelle Webdokument einzubetten, verwenden Sie unter Verwendung seiner ID ICefDomDocument.getElementById(). Aber wie finden Sie Elemente durch das Attribut NAME? Javascript hat die document.getElementsByName() -Methode und TWebBrowser (die IE umschließt) hat einen ähnlichen Anruf, aber ich kann nicht herausfinden, wie man das mit TChromium macht. Ich muss einige DOM-Elemente finden, die NAME-Attribute aber keine ID-Attribute haben. Ich suchte die ceflib Einheit und sah nichts, was es tun würde.Wie erhält man Elemente in Delphi Chromium Embedded?

Seitliche Frage. Wenn jemand einen Link zu einer TChromium "Rezeptstil" -Seite oder einem Dokument hat, könnte ich es verwenden.

UPDATE: Während ich auf eine Antwort wartete, habe ich den folgenden Code für getElementsbyName() gefunden. Ich hätte gerne etwas schneller, als den gesamten DOM-Baum zu scannen. Wenn Sie etwas falsch im Code sehen lassen Sie mich wissen:

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

Ich glaube nicht, es klug ist, und mit dem Stand der Technik Zeugs 10 Jahre alte Technik zu entsprechen zu mischen und zu erwarten, dass es eine gefunden und stabile Lösung werden. In diesem speziellen Fall unterstützt TChrium Delph 6 nicht. Http://code.google.com/p/delphichromiumedmbedded/ –

+0

@ Jeroen, das [TChromium] (http://code.google.com/p/delphichromiumedmbedded) /) unterstützt Delphi 6 zwar nicht (es gibt kein Paket dafür), aber es bedeutet nicht, dass es dort nicht funktionieren könnte. Ich habe Delphi 2009, das auch nicht unterstützt wird, aber wenn man sich die Quelle anschaut, gibt es nichts, was die Verwendung dort hemmen könnte ;-) – TLama

+0

@TLama Wenn mir meine Gedanken gut genug sind, hat Delphi 7 einige Fixes zum Umwickeln von COM-Sachen eingeführt. Das könnte ein Grund sein, Delphi 6 nicht zu unterstützen. Ich würde Robert empfehlen, diese Annahme mit dem TChrium-Team zu überprüfen. –

Antwort

3

Es gibt keine Funktion wie von JavaScript ist getElementsByName oder getElementsByName im Chromium Embedded gebaut MSHTML noch ihre Delphi-Wrapper zu diesem Zeitpunkt. Sie können dies nur lösen, indem Sie über alle DOM-Elemente, z. Erstellen Sie Ihre eigene DOM-Besucherklasse wie folgt:

Bitte beachten Sie, die VisitDom Prozedur ist asynchron, so dass es sofort zurückkehrt (tatsächlich bevor der DOM-Besucher seine visit beendet) und es mit einer Momentaufnahme des DOM zum Zeitpunkt der Ausführung funktioniert .

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: das Rad neu erfinden. Nicht absichtlich, ich benutze nur das, was ich gefunden habe, als ich Chromium mit Delphi erforscht habe (siehe meine Antwort auf deinen Kommentar zum Hauptbeitrag). –

+0

Also nehme ich an, dass der Aufruf Besuch mit einem Nachkomme TCefDomVisitorOwn das Besuchermuster implementiert? Mit anderen Worten, CEF wendet dieses Muster auf alle Knoten im DOM an und behandelt den rekursiven Abstieg durch den Knotenbaum für Sie? Das ist sehr cool, wenn es so ist, aber ich möchte absolut sicher sein, darum bitte ich um Bestätigung. –

+0

Nein, die Iteration müssen Sie immer noch selbst machen. Der Unterschied bei der Verwendung der 'VisitDom'-Methode besteht darin, dass eine Kopie (ein Snapshot) des aktuellen DOM-Zustands erstellt wird. In meinem Beispiel arbeitet der 'TElementNameVisitor.visit' mit einer Kopie des Dokuments, nicht mit dem Dokument selbst (das zum Zeitpunkt der Iteration geändert werden kann). Ich weiß nicht, ob es schneller ist, es ist nur sicherer. – TLama

Verwandte Themen