2012-05-20 35 views
5

Para obtener un nodo DOM particular incrustado en el documento web actual de una instancia TChromium, utilizando su ID, utiliza ICefDomDocument.getElementById(). ¿Pero cómo encuentras elementos por el atributo NAME? Javascript tiene el método document.getElementsByName() y TWebBrowser (que envuelve IE) tiene una llamada similar, pero no puedo encontrar la manera de hacerlo con TChromium. Necesito encontrar algunos elementos DOM que tengan atributos NAME pero no atributos de ID. Busqué en la unidad ceflib y no vi nada que lo hiciera.¿Cómo obtener elementos por nombre en Delphi Chromium Embedded?

Pregunta lateral. Si alguien tiene un enlace a un sitio o documento de estilo de "recetas" de TChromium, podría usarlo.

ACTUALIZACIÓN: Mientras espero una respuesta, he encontrado el siguiente código para hacer getElementsbyName(). Me gustaría algo más rápido que escanear todo el árbol DOM. Si usted ve algo mal en el código que me haga saber:

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

No creo que sea sensato mezclar y combinar la tecnología de 10 años con lo último en tecnología y esperar que se convierta en una solución estable y estable. En este caso particular, TChromium no es compatible con Delph 6. http://code.google.com/p/delphichromiumembedded/ –

+0

@Jeroen, el ['TChromium'] (http://code.google.com/p/delphichromiumembedded /) no es compatible con Delphi 6 (no hay paquete para él), pero no significa que no podría funcionar allí. Tengo Delphi 2009, que tampoco es compatible, pero al buscar en source, no hay nada que pueda inhibir el uso allí ;-) – TLama

+0

@TLama, si mi mente me sirve lo suficiente, Delphi 7 introdujo bastantes correcciones relacionadas con el ajuste de cosas COM. Esa podría ser una razón para no apoyar a Delphi 6. Recomiendo a Robert que verifique esta suposición con el equipo de TChromium. –

Respuesta

3

no hay ninguna función como JavaScript de getElementsByName o MSHTML getElementsByName construido en el Chromium Embedded ni su envoltorio Delphi en este momento. Puede resolver esto solo iterando sobre todos los elementos DOM, p. Ej. mediante la creación de su propia clase DOM visitante de esta manera:

Tenga en cuenta el procedimiento VisitDom es asíncrona, por lo que devuelve de inmediato (en realidad antes de que el visitante DOM termina su visit) y funciona con una instantánea de la DOM en el momento en que es ejecutado .

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: reinventar la rueda. No a propósito, simplemente usando lo que encontré cuando investigaba usando Chromium con Delphi (ver mi respuesta a tu comentario en la publicación principal). –

+0

Entonces, ¿deduzco que la visita de llamada con un descendiente TCefDomVisitorOwn implementa el patrón de visitante? En otras palabras, CEF aplicará ese patrón a todos los nodos en el DOM, manejando el descenso recursivo a través del árbol de nodos por usted. Eso es genial si es así, pero quiero estar absolutamente seguro, así que estoy pidiendo confirmación. –

+0

No, la iteración que tiene que hacer aún por su cuenta. La diferencia de usar el método 'VisitDom' es que hace una copia (una instantánea) del estado DOM actual. En mi ejemplo, 'TElementNameVisitor.visit' funciona con una copia del documento, no con el documento en sí (que puede modificarse en el momento de la iteración). No sé si es más rápido, es más seguro. – TLama

Cuestiones relacionadas