Парсер XML
01.01.2007
{ **** UBPFD *********** by kladovka.net.ru ****
>> Разбор XML
Данный прасер не такой универсальный, как предыдущий, за то - почти в 1000 раз эффективнее!
Зависимости: Windows, Forms, SysUtils, StrUtils
Автор: Delirium, VideoDVD@hotmail.com, ICQ:118395746, Москва
Copyright: Delirium (Master BRAIN) 2003
Дата: 22 октября 2003 г.
********************************************** }
unit BNFXMLParser2;
interface
uses Windows, Forms, SysUtils, StrUtils;
type
PXMLNode=^TXMLNode;
PXMLTree=^TXMLTree;
TXMLAttr=record
NameIndex, NameSize:integer;
TextIndex, TextSize:integer;
end;
TXMLNode=record
NameIndex, NameSize:integer;
Attributes:array of TXMLAttr;
TextIndex, TextSize:integer;
SubNodes:array of PXMLNode;
Parent:PXMLNode;
Data:PString;
end;
TXMLTree=record
Data:PString;
TextSize:integer;
NodesCount:integer;
Nodes:array of PXMLNode;
end;
function BNFXMLTree(Value:String):PXMLTree;
function GetXMLNodeName(Node:PXMLNode):String;
function GetXMLNodeText(Node:PXMLNode):String;
function GetXMLNodeAttr(AttrName:String; Node:PXMLNode):String;
implementation
function BNFXMLTree(Value:String):PXMLTree;
var LPos, k, State, CurAttr:integer;
i:integer;
CurNode:PXMLNode;
begin
New(Result);
Result^.TextSize:=Pos('<', Value)-1;
New(Result^.Data);
Result^.Data^:=Value;
k:=0;
State:=0;
CurNode:=nil;
CurAttr:=-1;
for LPos:=Result.TextSize+1 to Length(Value) do
case State of
0:case Value[LPos] of
'<':begin
i:=length(Result.Nodes);
Setlength(Result.Nodes, i+1);
New(Result.Nodes[i]); Inc(k);
if k mod 10 = 0 then
begin
Application.ProcessMessages;
if k mod 100 = 0 then SleepEx(1, True);
end;
CurNode:=Result.Nodes[i];
CurNode^.NameIndex:=0;
CurNode^.NameSize:=0;
CurNode^.TextIndex:=0;
CurNode^.Parent:=nil;
CurNode^.Data:=Result^.Data;
State:=1;
end;
end;
1:case Value[LPos] of
' ':;
'>':State:=9;
'/':State:=10;
else begin
CurNode^.NameIndex:=LPos;
CurNode^.NameSize:=1;
State:=2;
end;
end;
2:case Value[LPos] of
' ':State:=3;
'>':State:=9;
'/':State:=10;
else Inc(CurNode^.NameSize);
end;
3:case Value[LPos] of
' ':;
'>':State:=9;
'/':State:=10;
else begin
i:=length(CurNode^.Attributes);
Setlength(CurNode^.Attributes, i+1);
CurNode^.Attributes[i].NameIndex:=LPos;
CurNode^.Attributes[i].NameSize:=1;
CurAttr:=i;
State:=4;
end;
end;
4:case Value[LPos] of
'=':State:=5;
else Inc(CurNode^.Attributes[CurAttr].NameSize);
end;
5:case Value[LPos] of
'''':State:=6;
'"':State:=7;
end;
6:case Value[LPos] of
'''':begin
CurNode^.Attributes[CurAttr].TextIndex:=LPos;
CurNode^.Attributes[CurAttr].TextSize:=0;
State:=8;
end;
else begin
CurNode^.Attributes[CurAttr].TextIndex:=LPos;
CurNode^.Attributes[CurAttr].TextSize:=1;
State:=61;
end;
end;
7:case Value[LPos] of
'"':begin
CurNode^.Attributes[CurAttr].TextIndex:=LPos;
CurNode^.Attributes[CurAttr].TextSize:=0;
State:=8;
end;
else begin
CurNode^.Attributes[CurAttr].TextIndex:=LPos;
CurNode^.Attributes[CurAttr].TextSize:=1;
State:=71;
end;
end;
61:case Value[LPos] of
'''':State:=8;
else Inc(CurNode^.Attributes[CurAttr].TextSize);
end;
71:case Value[LPos] of
'"':State:=8;
else Inc(CurNode^.Attributes[CurAttr].TextSize);
end;
8:case Value[LPos] of
' ':State:=3;
'>':State:=9;
'/':State:=10;
end;
9:case Value[LPos] of
'<':State:=12;
else begin
CurNode^.TextIndex:=LPos;
CurNode^.TextSize:=1;
State:=11;
end;
end;
10:case Value[LPos] of
'>':begin
CurNode:=CurNode^.Parent;
if CurNode=nil
then State:=0
else State:=9;
end;
end;
11:case Value[LPos] of
'<':State:=12;
else Inc(CurNode^.TextSize);
end;
12:case Value[LPos] of
'/':State:=10;
else begin
i:=length(CurNode^.SubNodes);
Setlength(CurNode^.SubNodes, i+1);
New(CurNode^.SubNodes[i]); Inc(k);
if k mod 10 = 0 then
begin
Application.ProcessMessages;
if k mod 100 = 0 then SleepEx(1, True);
end;
CurNode^.SubNodes[i]^.Parent:=CurNode;
CurNode^.SubNodes[i]^.Data:=Result^.Data;
CurNode^.SubNodes[i].NameIndex:=LPos;
CurNode^.SubNodes[i].NameSize:=1;
CurNode^.SubNodes[i].TextIndex:=0;
CurNode:=CurNode^.SubNodes[i];
State:=2;
end;
end;
end;
Result^.NodesCount:=k;
end;
function GetXMLNodeName(Node:PXMLNode):String;
begin
Result:=Copy(Node^.Data^, Node^.NameIndex, Node^.NameSize);
end;
function GetXMLNodeText(Node:PXMLNode):String;
begin
Result:=Copy(Node^.Data^, Node^.TextIndex, Node^.TextSize);
end;
function GetXMLNodeAttr(AttrName:String; Node:PXMLNode):String;
var i:integer;
begin
Result:='';
if Length(Node^.Attributes)=0 then exit;
i:=0;
while (i<Length(Node^.Attributes))
and (AnsiLowerCase(AttrName)<>AnsiLowerCase(Trim(Copy(Node^.Data^, Node^.Attributes[i].NameIndex, Node^.Attributes[i].NameSize))))
do Inc(i);
Result:=Copy(Node^.Data^, Node^.Attributes[i].TextIndex, Node^.Attributes[i].TextSize);
end;
end.