Simple HTML Parser

migajek

W jaki sposob "wyciągnąć" z wskazanego taga HTML jego właściwości?
Funkcja zwraca rekord, w ktorym mamy nazwe "zparsowanego" taga oraz tablice z właściwościami (nazwa_wlasciwosci,wartosc).
Kod jest bardzo niedoskonały, ale ma mozliwosc wyciagania wartosci z tagow w formacie

nazwa="wartosc"
nazwa='wartosc'
nazwa=wartosc

Narazie nie bylo to testowane na wielu plikach, no ale zawsze cos :)
Jeśli znajdziesz jakikolwiek błąd, napisz do mnie na migajek(Eustachy)yahoo(Zdzisiek)com

Proszę o ocenę i sugestie :)
A oto kod:

(*|*******************************|*)
(*|   Simple HTML Parser v.0.0.1  |*)
(*|         Copyright 2005        |*)
(*|         by Michał Gajek       |*)
(*|     All rights reserved       |*)
(*|     http://www.migajek.com    |*)
(*|       [email protected]       |*)

(*
ToDo :
[x] obslugiwac tagi bez wlasnosci (np <b>, <br> itp) 
[x] pobierac dokladniej nazwy parametrow
[ ] tagi w formacie nazwa = "wartosc" czasem nawalaja
*)

unit HTMLParser;

interface

uses
    Windows, Messages, SysUtils, Variants, Classes, Graphics, Controls, Forms,Dialogs;

type
 THTMLParsedValue = record
  Name : string;
  Value : string;
 end;
 THTMLParsedValues = record
  TagName:string;
  Values: array of THTMLParsedValue;
 end;

function ParseHTML(s:string;TagName:string):THTMLParsedValues;
implementation


function ParseHTML(s:string;TagName:string):THTMLParsedValues;
const
 DivTag : char = '|';
var
res:THTMLParsedValues;
TagBeginPos,TagEndPos:integer;
TagStr,TagContent:string;
i,j:integer;
InValue:bool; //czy jestesmy w wartosci jakiejs?
ts:TStringList;
begin
inValue:=false;
TagBeginPos:=pos(tagName,s);
//if TagName='' then TagBeginPos:=1; //jak pusty to na 1 :D
TagEndPos:= pos('>',copy(s,TagBeginPos,length(s)));
TagStr:=Copy(s,TagBeginPos,TagEndPos); //wyciety tag
if pos(' ',tagstr)<>0 then
 res.TagName:=copy(tagstr,pos('<',tagstr)+1,pos(' ',tagstr)-1)//nazwa taga
else
 res.TagName:=copy(tagstr,pos('<',tagstr)+1,pos('>',tagstr)-2);//nazwa taga

TagContent:=copy(TagStr,length(res.TagName)+2,length(tagstr)-length(tagname)-2);//zawartosc (czyli bez nazwy i koncowki)
if tagcontent = '' then exit;

{=== usuwanie zbednych spacjii ===}
for i:=length(Tagcontent) downto 1 do
 begin
 if (TagContent[i]= '"')or(TagContent[i]= #$27) then //jesli znaleziono poczatek lub koniec lanucha
 begin
  if TagContent[i+1] <>'' then //jesli nie jest to zakonczenie/poczatek
   begin
   InValue:=not InValue; //zmieniamy wartosc
    if InValue then
     Insert(DivTag,TagContent,i+1); //wstawiamy tag rozdzielenia
   end;
 end;

 if (TagContent[i] = ' ') and (TagContent[i+1]= ' ') then //jesli swie spacje pod rzad
  if not inValue then //jesli w wartosci
   Delete(TagContent,i,1); //skasuj
 end;
//sshowmessage(tagcontent);
for i:=length(Tagcontent) downto 1 do
 begin
  if (TagContent[i]='"')or(TagContent[i]=#$27) then
   if TagContent[i-1] ='' then
    Delete(TagContent,i-1,1)
   else
    Delete(TagContent,i,1)
 end;
//usuwanie spacji z nazwy taga
 if res.TagName<>'' then
 begin
  while res.TagName[1] = ' ' do
   Delete(res.TagName,1,1);
  while res.TagName[length(res.TagName)] = ' ' do
   Delete(res.TagName,length(res.TagName),1);
 end;

//usuwanie znakow z poczatku i konca lini
if TagContent<>'' then
 begin
  while TagContent[1] = ' ' do
   Delete(TagContent,1,1);
  while TagContent[length(tagcontent)] = ' ' do
   Delete(TagContent,length(tagcontent)-1,1);
 end;
ts:=TStringList.Create;
ExtractStrings([DivTag],[' '],PChar(tagcontent),ts);
for j:=0 to ts.Count-1 do
 begin
  if Copy(ts.Strings[j],1,pos('=',ts.Strings[j])-1)<>'' then
  begin
  SetLength(res.Values,Length(res.Values)+1);
  res.Values[high(res.values)].Name:=Copy(ts.Strings[j],1,pos('=',ts.Strings[j])-1);
  res.Values[high(res.values)].Value:=Copy(ts.Strings[j],length(res.Values[high(res.values)].Name)+2,length(ts.Strings[j]));
  if res.Values[high(res.values)].Name<>'' then
   begin
    while res.Values[high(res.values)].Name[1] = ' ' do
     Delete(res.Values[high(res.values)].Name,1,1);
    while res.Values[high(res.values)].Name[length(res.Values[high(res.values)].Name)] = ' ' do
     Delete(res.Values[high(res.values)].Name,length(res.Values[high(res.values)].Name)-1,1);
   end;

  end; 
 end;
result:=res;
end;
end.

11 komentarzy

DJ Orange: raczej nie :]

A ten twoj edytor html bedzie Open Source <lol> ?

Wolverine: thx za linka, ale samemu czasem tez warto :) No ale moze sie przydac, jak trzeba bedzie dopracowywac :)

Polecam http://regexpstudio.com/, latwiej sie takie rzeczy robi.

Poprawiłem troche kod, mam nadzieje ze bedzie lepiej dzialac.

O sorry... Parser powstal na potrzeby mojego edytora html i po prostu zostalo tam w uses... :P Wywal to :P

MemoUtils i Decl to jakies dodatkowe komponenty ? :| bo przy kompilacji na d7 ent. wyskakuje ze brak wlasnie tego :|

przydzało by sie tez na formę taką:

nazwa = "wartość"

czyli ze spacjami, w rożnych kombinacjach of course.. no chyba, że już to masz - nie testowałem.

Deti: nie mam chyba :P Jeszcze sie moze pobawie... Jak cos zmienie to napisze :)

Marooned : ta, wiem... po prostu najpierw pisalem arta a potem wklejalem tresc pliku ;)
p.s. serio? :P

Ukryłeś maila przed botami "migajek(Eustachy)yahoo(Zdzisiek)com" a 5 linijek niżej podałeś w normalnej formie :]
p.s. pisze się 'na razie' ;)