在Delphi Chromium Embedded中如何获取元素? [英] How to get elements by name in Delphi Chromium Embedded?

查看:1781
本文介绍了在Delphi Chromium Embedded中如何获取元素?的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

要从TChromium实例获取嵌入在当前Web文档中的特定DOM节点,使用其ID,可以使用ICefDomDocument.getElementById()。但是如何通过NAME属性找到元素? Javascript有document.getElementsByName()方法和TWebBrowser(它包装IE)有类似的调用,但我不知道如何使用TChromium。我需要找到一些具有NAME属性但没有ID属性的DOM元素。我搜索了 ceflib 单元,没有看到任何可能的事情。

To get a particular DOM node embedded in the current web document from a TChromium instance, using its ID, you use ICefDomDocument.getElementById(). But how do you find elements by the NAME attribute? Javascript has the document.getElementsByName() method and TWebBrowser (that wraps IE) has a similar call, but I can't figure out how to do this with TChromium. I need to find some DOM elements that have NAME attributes but no ID attributes. I searched the ceflib unit and did not see anything that would do it.

侧面的问题。如果有人链接到TChromium食谱风格的网站或文档,我可以使用它。

Side question. If anyone has a link to a TChromium "recipes" style site or document I could use it.

更新:在等待一个答案的时候,我已经提出了以下代码做getElementsbyName()。我想要比扫描整个DOM树更快的东西。如果您在代码中看到错误,请告诉我:

UPDATE: While waiting for an answer I have come up with the following code for doing getElementsbyName(). I'd like something faster than scanning the entire DOM tree. If you see something wrong in the code let me know:

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;

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


推荐答案

没有JavaScript的 getElementsByName 或MSHTML getElementsByName 内置 Chromium Embedded 及其Delphi包装器。您只能通过遍历所有DOM元素来解决此问题。通过创建您自己的DOM访问类,如下所示:

There is no function like JavaScript's getElementsByName or MSHTML getElementsByName built in the Chromium Embedded nor its Delphi wrapper at this time. You can resolve this only by iterating over all DOM elements, e.g. by creating your own DOM visitor class like this:

请注意, VisitDom 过程是异步的,因此它立即返回(实际上在DOM访问者完成访问之前),它在执行时与DOM的快照一起工作。

Please note the VisitDom procedure is asynchronous, so it returns immediately (actually before the DOM visitor finishes its visit) and it works with a snapshot of the DOM at the time it's executed.

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;

这篇关于在Delphi Chromium Embedded中如何获取元素?的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆