要使用其ID从TChromium实例获取当前Web文档中嵌入的特定DOM节点,请使用ICefDomDocument.getElementById().但是如何通过NAME属性找到元素? Javascript具有document.getElementsByName()方法,而TWebBrowser(包装IE)也有类似的调用,但我无法弄清楚如何使用TChromium执行此操作.我需要找到一些具有NAME属性但没有ID属性的DOM元素.我搜查了ceflib单位并没有看到任何可以做到的事情.
边题.如果有人链接到TChromium“食谱”风格的网站或文档,我可以使用它.
更新:在等待答案时,我已经提出了以下代码来执行getElementsbyName().我想要比扫描整个DOM树更快.如果您在代码中看到错误,请告诉我:
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,Result); end; // if Assigned(intfCefDomNode) then end; // if Assigned(ADocoument) then end; // ---------------------------------------------------------------
解决方法
目前还没有像
Chromium Embedded
中内置的JavaScript
getElementsByName
或MSHTML
getElementsByName
以及它的Delphi包装器那样的功能.您只能通过迭代所有DOM元素来解决此问题,例如:通过创建自己的DOM访问者类,如下所示:
请注意,VisitDom过程是异步的,因此它会立即返回(实际上在DOM访问者完成访问之前)并且它在执行时与DOM的快照一起工作.
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;