Sources
Delphi Russian Knowledge Base
DRKB - это самая большая и удобная в использовании база знаний по Дельфи в рунете, составленная Виталием Невзоровым

Парсер 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.