Delphi html 解析检查元素是否有属性
Delphi html parsing check if element has attribute
我有以下程序:
class procedure ParseData(AData: string; var ATextList: TList<string>);
var
HTMLDoc: OleVariant;
HTMLElement: OleVariant;
I: Integer;
begin
HTMLDoc := coHTMLDocument.Create as IHTMLDocument2;
HTMLDoc.Write(AData);
HTMLDoc.Close;
for I := 0 to HTMLDoc.body.all.length - 1 do
begin
HTMLElement := HTMLDoc.body.all.item(I);
if HTMLElement.hasAttribute('attr1') then
ATextList.Add(HTMLElement.innerHTML);
end;
end;
问题是 hasAttribute
不工作。 setattribute
、innerHTML
、tagName
等函数和程序运行良好。还有另一种方法来检查元素是否包含给定的属性吗?
您可以像这样检查特定的命名属性:
function HasAttribute(ANode : IHtmlDomNode; const AttrName : String) : Boolean;
var
Attrs : IHtmlAttributeCollection;
A : IHtmlDomAttribute;
V : OleVariant;
i : Integer;
begin
Result := ANode.nodeType = 1;
if not Result then
Exit;
Attrs := IDispatch(ANode.Attributes) as IHtmlAttributeCollection;
for i := 0 to Attrs.length - 1 do begin
V := i;
A := IDispatch(Attrs.item(V)) as IHtmlDomAttribute;
if CompareText(AttrName, A.nodeName) = 0 then
exit;
end;
Result := False;
end;
procedure TForm1.btnTestAttributesClick(Sender: TObject);
var
D : IHtmlDomNode;
AttrName : String;
Msg : String;
begin
D := IDispatch(WebBrowser1.OleObject.Document.GetElementByID('input1')) as IHtmlDomNode;
AttrName := 'attr1';
if HasAttribute(D, AttrName) then
Msg := 'Found'
else
Msg := 'Not found';
Memo1.Lines.Add(AttrName + ' : ' + Msg);
AttrName := 'value';
if HasAttribute(D, AttrName) then
Msg := 'Found'
else
Msg := 'Not found';
Memo1.Lines.Add(AttrName + ' : ' + Msg);
end;
我建议使用您自己的 HasAttribute 函数的原因是 MSHTML 解析器在节点的 'value' 属性方面存在问题,如我对 [=16= 的回答中所述]
Checking whether there are <input> object attribute values in the HTML Code using Delphi
使用 HTML 我包括:
<html>
<body>
<p>This has no value attribute.
<input name="input1" type="text"/>
<p>This has an empty value attribute.
<input name="input2" type="text" value=""/>
<p>This has a value attribute.
<input name="input3" type="text" value="already has a value"/>
</body>
</html>
您会发现 DumpItems 例程报告 IHtmlAttributeCollection 包含名为 'value' 的节点,无论 HTML 的源中是否存在具有该名称的属性。参见例如第一个 Input 节点的结果。如果节点的 HTML.
中没有定义,就好像 DOM 解析器合成了一个 'value' 节点
代码的 DumpItems 报告示例 HTML 的以下内容:
Node name: INPUT
value:
147: type: >text<
158: value: ><
160: name: >input1<
Node name: INPUT
value:
147: type: >text<
158: value: ><
160: name: >input2<
Node name: INPUT
value:
147: type: >text<
158: value: >already has a value<
160: name: >input3<
顺便说一句,当我第一次 运行 我的测试应用程序时,报告的属性节点编号 (147、158、160) 让我感到困惑,但原因是每个 IHtmlDomNode 都有一大堆属性, 主要是事件处理程序,以 onchange
.
开头
为了避免查看其他答案,其 DumpItems 的代码是
procedure TForm1.DumpItems;
var
E : IHtmlElement;
D : IHtmlDomNode;
procedure DumpNode(ANode : IHtmlDomNode);
var
Attrs : IHtmlAttributeCollection;
A : IHtmlDomAttribute;
V : OleVariant;
i : Integer;
begin
Log('Node name', ANode.nodeName);
V := ANode.nodeValue;
if not VarIsNull(V) and not VarIsEmpty(V) then
Log(' value', V)
else
Log(' value', '');
Attrs := IDispatch(ANode.Attributes) as IHtmlAttributeCollection;
for i := 0 to Attrs.length - 1 do begin
V := i;
A := IDispatch(Attrs.item(V)) as IHtmlDomAttribute;
V := A.nodeValue;
if (CompareText(A.nodeName, 'Name') = 0) or (CompareText(A.nodeName, 'Input') = 0) or (CompareText(A.nodeName, 'Type') = 0) or (CompareText(A.nodeName, 'Value') = 0) then begin
if not VarIsNull(V) and not VarIsEmpty(V) then
Log(' ' + IntToStr(i) + ': ' + A.nodeName, '>' + V + '<')
else
Log(' ' + IntToStr(i) + ': '+ A.nodeName, '')
end;
end;
end;
begin
D := IDispatch(WebBrowser1.OleObject.Document.GetElementByID('input1')) as IHtmlDomNode;
DumpNode(D);
D := IDispatch(WebBrowser1.OleObject.Document.GetElementByID('input2')) as IHtmlDomNode;
DumpNode(D);
D := IDispatch(WebBrowser1.OleObject.Document.GetElementByID('input3')) as IHtmlDomNode;
DumpNode(D);
end;
您可以测试:
if not VarIsNull(HTMLElement.getAttribute('attr1')) then
ATextList.Add(HTMLElement.innerHTML);
编辑:
hasAttribute
在 IHTMLElement5
接口中实现 - 它需要 IE8 及更高版本,并且在 IE7 标准模式或 IE5 (Quirks) 模式下不受支持。
我导入了 C:\Windows\System32\mshtml.tlb
(使用 tlibimp
工具),此代码有效:
if (IDispatch(HTMLElement) as IHTMLElement5).hasAttribute('attr1') then...
我有以下程序:
class procedure ParseData(AData: string; var ATextList: TList<string>);
var
HTMLDoc: OleVariant;
HTMLElement: OleVariant;
I: Integer;
begin
HTMLDoc := coHTMLDocument.Create as IHTMLDocument2;
HTMLDoc.Write(AData);
HTMLDoc.Close;
for I := 0 to HTMLDoc.body.all.length - 1 do
begin
HTMLElement := HTMLDoc.body.all.item(I);
if HTMLElement.hasAttribute('attr1') then
ATextList.Add(HTMLElement.innerHTML);
end;
end;
问题是 hasAttribute
不工作。 setattribute
、innerHTML
、tagName
等函数和程序运行良好。还有另一种方法来检查元素是否包含给定的属性吗?
您可以像这样检查特定的命名属性:
function HasAttribute(ANode : IHtmlDomNode; const AttrName : String) : Boolean;
var
Attrs : IHtmlAttributeCollection;
A : IHtmlDomAttribute;
V : OleVariant;
i : Integer;
begin
Result := ANode.nodeType = 1;
if not Result then
Exit;
Attrs := IDispatch(ANode.Attributes) as IHtmlAttributeCollection;
for i := 0 to Attrs.length - 1 do begin
V := i;
A := IDispatch(Attrs.item(V)) as IHtmlDomAttribute;
if CompareText(AttrName, A.nodeName) = 0 then
exit;
end;
Result := False;
end;
procedure TForm1.btnTestAttributesClick(Sender: TObject);
var
D : IHtmlDomNode;
AttrName : String;
Msg : String;
begin
D := IDispatch(WebBrowser1.OleObject.Document.GetElementByID('input1')) as IHtmlDomNode;
AttrName := 'attr1';
if HasAttribute(D, AttrName) then
Msg := 'Found'
else
Msg := 'Not found';
Memo1.Lines.Add(AttrName + ' : ' + Msg);
AttrName := 'value';
if HasAttribute(D, AttrName) then
Msg := 'Found'
else
Msg := 'Not found';
Memo1.Lines.Add(AttrName + ' : ' + Msg);
end;
我建议使用您自己的 HasAttribute 函数的原因是 MSHTML 解析器在节点的 'value' 属性方面存在问题,如我对 [=16= 的回答中所述]
Checking whether there are <input> object attribute values in the HTML Code using Delphi
使用 HTML 我包括:
<html>
<body>
<p>This has no value attribute.
<input name="input1" type="text"/>
<p>This has an empty value attribute.
<input name="input2" type="text" value=""/>
<p>This has a value attribute.
<input name="input3" type="text" value="already has a value"/>
</body>
</html>
您会发现 DumpItems 例程报告 IHtmlAttributeCollection 包含名为 'value' 的节点,无论 HTML 的源中是否存在具有该名称的属性。参见例如第一个 Input 节点的结果。如果节点的 HTML.
中没有定义,就好像 DOM 解析器合成了一个 'value' 节点代码的 DumpItems 报告示例 HTML 的以下内容:
Node name: INPUT
value:
147: type: >text<
158: value: ><
160: name: >input1<
Node name: INPUT
value:
147: type: >text<
158: value: ><
160: name: >input2<
Node name: INPUT
value:
147: type: >text<
158: value: >already has a value<
160: name: >input3<
顺便说一句,当我第一次 运行 我的测试应用程序时,报告的属性节点编号 (147、158、160) 让我感到困惑,但原因是每个 IHtmlDomNode 都有一大堆属性, 主要是事件处理程序,以 onchange
.
为了避免查看其他答案,其 DumpItems 的代码是
procedure TForm1.DumpItems;
var
E : IHtmlElement;
D : IHtmlDomNode;
procedure DumpNode(ANode : IHtmlDomNode);
var
Attrs : IHtmlAttributeCollection;
A : IHtmlDomAttribute;
V : OleVariant;
i : Integer;
begin
Log('Node name', ANode.nodeName);
V := ANode.nodeValue;
if not VarIsNull(V) and not VarIsEmpty(V) then
Log(' value', V)
else
Log(' value', '');
Attrs := IDispatch(ANode.Attributes) as IHtmlAttributeCollection;
for i := 0 to Attrs.length - 1 do begin
V := i;
A := IDispatch(Attrs.item(V)) as IHtmlDomAttribute;
V := A.nodeValue;
if (CompareText(A.nodeName, 'Name') = 0) or (CompareText(A.nodeName, 'Input') = 0) or (CompareText(A.nodeName, 'Type') = 0) or (CompareText(A.nodeName, 'Value') = 0) then begin
if not VarIsNull(V) and not VarIsEmpty(V) then
Log(' ' + IntToStr(i) + ': ' + A.nodeName, '>' + V + '<')
else
Log(' ' + IntToStr(i) + ': '+ A.nodeName, '')
end;
end;
end;
begin
D := IDispatch(WebBrowser1.OleObject.Document.GetElementByID('input1')) as IHtmlDomNode;
DumpNode(D);
D := IDispatch(WebBrowser1.OleObject.Document.GetElementByID('input2')) as IHtmlDomNode;
DumpNode(D);
D := IDispatch(WebBrowser1.OleObject.Document.GetElementByID('input3')) as IHtmlDomNode;
DumpNode(D);
end;
您可以测试:
if not VarIsNull(HTMLElement.getAttribute('attr1')) then
ATextList.Add(HTMLElement.innerHTML);
编辑:
hasAttribute
在 IHTMLElement5
接口中实现 - 它需要 IE8 及更高版本,并且在 IE7 标准模式或 IE5 (Quirks) 模式下不受支持。
我导入了 C:\Windows\System32\mshtml.tlb
(使用 tlibimp
工具),此代码有效:
if (IDispatch(HTMLElement) as IHTMLElement5).hasAttribute('attr1') then...