Formatowanie kodu HTML

Deti

.. jak w temacie

Najpierw do sekcji type dopisz sobie pomocniczy typ, który będzie reprezentował typ znacznika (tagu) HTML:

THTMLLine = (TgFormatO, TgFormatC, None);

Teraz możecie zrobić sobie tablice, która będzie zawierać tzw. tagi formatowane czyli te, przy których będą wcięcia:

IndentTags: array[1..22] of Shortstring = ('head', 'body', 'table', 'tr', 'td', 'p', 'h1', 'h2', 'h3', 'h4', 'h5', 'h6', 'ul', 'ol', 'center', 'cite', 'code', 'div', 'span', 'form', 'script', 'style'); // Tagi formatowane

No i w końcu gwóźdź programu:

function HTMLFormat(s: string): string;
{
Funkcja formatująca kod HTML
ver 1.0 alpha
--------------------------------
Autor: DetoX
detox@xlan.pl
}

var
  i: Integer;
  InnBuffer, TagBuffer, IndentAff: string;
  TR: TStringList; 
  HTMLLnArr: array of THTMLLine;

  function IsSpaces(ALine: string): Boolean; 
  // Sprawdza, czy linia kodu to same spacje
  var
    g: Integer;
  begin
    Result := True;
    for g := 1 to length(ALine) do
      if ALine[g] <> ' ' then
        Result := False;
  end;

  function RemoveBlanks(ALine: string): string;
  // Wycinanie spacji z początku linii kodu HTML
  begin
    while ALine[1] = ' ' do
      Delete(ALine, 1, 1);
    Result := ALine;
  end;

  function IsFormatted(ATag: string): Boolean;
  // Sprawdzanie, czy znacznik jest "formatowany"
  var
    g: Integer;
  begin
    Result := False;
    Atag := AnsiLowerCase(ATag);
    for g := Low(IndentTags) to High(IndentTags) do
      if IndentTags[g] = ATag then
        Result := True;
  end;

begin

  // Dla bezpieczeństwa
  if length(s) = 0 then
  begin
    Result := '';
    Exit;
  end;

  // Rozdzielenie tagów formatowanych na wiersze
  for i := Low(IndentTags) to High(IndentTags) do
  begin
    InnBuffer := s;
    while Boolean(pos('<' + IndentTags[i], InnBuffer)) do
    begin
      InnBuffer := Copy(InnBuffer, pos('<' + IndentTags[i], InnBuffer), length(InnBuffer) - pos('<' + IndentTags[i], InnBuffer));
      TagBuffer := Copy(InnBuffer, 1, pos('>', InnBuffer));
      Delete(InnBuffer, 1, pos('>', InnBuffer));
      s := AnsiReplaceStr(s, TagBuffer, #13 + TagBuffer + #13);
    end;
    while Boolean(pos('</' + IndentTags[i], InnBuffer)) do
    begin
      InnBuffer := Copy(InnBuffer, pos('</' + IndentTags[i], InnBuffer), length(InnBuffer) - pos('</' + IndentTags[i], InnBuffer));
      TagBuffer := Copy(InnBuffer, 1, pos('>', InnBuffer));
      Delete(InnBuffer, 1, pos('>', InnBuffer));
      s := AnsiReplaceStr(s, TagBuffer, #13 + TagBuffer + #13);
    end;
  end;

  // Usuwanie pustych linii i spacji na początku wierszy
  TR := TStringList.Create;
  TR.Text := s;
  for i := TR.Count - 1 downto 0 do
    if (TR[i] = '') or (IsSpaces(TR[i])) then
      TR.Delete(i)
    else if TR[i][1] = ' ' then
      TR[i] := RemoveBlanks(TR[i]);

  // Rozpoznanie tagów
  SetLength(HTMLLnArr, TR.Count);
  for i := 0 to TR.Count - 1 do
  begin
    if TR[i][1] <> '<' then
      HTMLLnArr[i] := None
    else if Boolean(pos('>', TR[i])) then
    begin
      if (IsFormatted(Copy(TR[i], 2, pos('>', TR[i]) - 2)) or IsFormatted(Copy(TR[i], 3, pos('>', TR[i]) - 3))) then
      begin
        if Copy(TR[i], 1, 2) = '</' then
          HTMLLnArr[i] := TgFormatC
        else
          HTMLLnArr[i] := TgFormatO;
      end
      else
      begin
        if (IsFormatted(Copy(TR[i], 2, pos(' ', TR[i]) - 2)) or IsFormatted(Copy(TR[i], 3, pos(' ', TR[i]) - 3))) then
        begin
          if Copy(TR[i], 1, 2) = '</' then
            HTMLLnArr[i] := TgFormatC
          else
            HTMLLnArr[i] := TgFormatO;
        end
        else HTMLLnArr[i] := None
      end;
    end
    else HTMLLnArr[i] := None;
  end;

  // Tworzenie wcięć
  IndentAff := '';
  for i := 1 to TR.Count - 2 do
  begin
    if ((HTMLLnArr[i] = None) and (HTMLLnArr[i - 1] = TgFormatO)) or ((HTMLLnArr[i] = TgFormatO) and (HTMLLnArr[i - 1] = TgFormatO)) then
      IndentAff := IndentAff + '  '
    else if ((HTMLLnArr[i] = TgFormatC) and (HTMLLnArr[i - 1] = TgFormatC)) or ((HTMLLnArr[i] = TgFormatC) and (HTMLLnArr[i - 1] = None)) then
      if length(IndentAff) >=2 then
        Delete(IndentAff, 1, 2);

    TR[i] := IndentAff + TR[i];

  end;

  Result := TR.Text;
  TR.Free;
end;

Kilka słów komentarza: funkcja działa poprawnie pod warunkiem, że kod HTML jest poprawny, to znaczy - sama nie może zamykać tagów itp - funkcja tylko odpowiednio je wyświetla, a nie modyfikuje. Jeśli ktoś ma jakieś pomysły na jej dopracowanie - prosiłbym o kontakt GG: 2849811 :)

4 komentarzy

-=ORanGE=- to działa tylko musisz wpisać poprawny kod html, czyli np. taki:

<html><head><title>TITLE</title></head><body></body></html>

to tylko przykład :)

Mnie to nie działa. (Deti mam kolego identycznego jak ty tak samo wygląda jak ty na tym zdjęciu :-)

try - finally?