How to get elements by name in Delphi Chromium Embedded?

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

Side question. If anyone has a link to a style site or a recipe based on TChromium recipes, I could use it.

UPDATE: waiting for a response, I came up with the following code to execute getElementsbyName (). I would 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; // --------------------------------------------------------------- 
+5
source share
1 answer

There is no function like JavaScript getElementsByName or MSHTML getElementsByName built in Chromium Embedded and its Delphi shell at that time. You can only resolve this by iterating over all the elements of the DOM, for example. creating your own DOM visitor class as follows:

Please note that the VisitDom procedure is asynchronous, so it returns immediately (in fact, before the DOM visitor finishes his visit ), and it works with the DOM snapshot at the time of its execution.

 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; 
+3
source

All Articles