在Delphi Chromium Embedded中如何获取元素? [英] How to get elements by name in 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屋!