Генерация XML

Вопросы программирования и использования среды Lazarus.

Модератор: Модераторы

Генерация XML

Сообщение [KIM] » 24.04.2013 02:25:21

Помогите, спасите, не ругайте!!!
В общем задача в следующем
Из вот такой таблицы
Код: Выделить всё
N   Name                           Parent_N         id

1   Двери                          0                cneljwnclwncvwjv
2   Входные двери                  1                hfwfcwefbcwebf
3   Бренд 1                        2                qtweqwytqycd
4   Бренд 2                        2                reihurevifvb
5   Межкомнатные двери             1                pjpjnkjnkn


Нужно получить XML следующего вида
Код: Выделить всё
<groups>
  <group>
  <id>cneljwnclwncvwjv</id>
  <sort>100</sort>
  <name>Двери</name>
  <picture>pic01.jpg</picture>
  </group>
  <groups>
    <group>
    <id>hfwfcwefbcwebf</id>
    <sort>100</sort>
    <name>Входные двери</name>
    <picture></picture>
    <groups>
      <group>
      <id>qtweqwytqycd</id>
      <sort>100</sort>
      <name>Бренд 1</name>
      <picture></picture>
      </group>
      <group>
      <id>reihurevifvb</id>
      <sort>200</sort>
      <name>Бренд 2</name>
      <picture></picture>
      </group>
      </groups>
      </group>
    <group>
    <id>pjpjnkjnkn</id>
    <sort>200</sort>
    <name>Межкомнатные двери</name>
    <picture></picture>
    </group>
  </groups>
</groups>



Перечитав кучу информации понял, что я тупо не могу проработать алгоритм(((
Голова трещит третий день, а решать задачу надо срочно.

Основная статья
http://wiki.freepascal.org/XML_Tutorial ... 0.BA.D0.B8
В принципе там всё понятно
Вот тут всё по человечески
http://wiki.freepascal.org/XML_Tutorial ... .D0.B0_XML
Но, не могу сообразить как мне углублять на вложенные уровни и как возвращаться((
Помогите пожалуйчста!!!
[KIM]
незнакомец
 
Сообщения: 5
Зарегистрирован: 22.03.2013 00:32:14

Re: Генерация XML

Сообщение vada » 24.04.2013 09:59:58

Такого типа не получится.
Вот так нельзя
Код: Выделить всё
<groups>
    <groups>
        <groups>
        </groups>
    </groups>
</groups>


Я не люблю заполнять тегами DOM. Беру просто строковый лист и в него добавляю нужные строки. Потом все сливаю в файл.
Код: Выделить всё
procedure CreatXML(........)
var
List:  TStringList;
begin
    List := TStringList.Create;
    List.Add('<?xml version="1.0" encoding="utf-8"?>');
    List.Add('<Data>');
    List.Add(#9'<CommonData>');
    List.Add(#9#9'<Program>KO206W</Program>');
    List.Add(#9#9'<ProgramName>'+
             'Расчет железобетонного сечения произвольной формы на прочность,'+
             'трещиностойкость и выносливость при действии продольной силы и изгибающих моментов.'+
             '</ProgramName>');
    List.Add(#9#9'<Version>'+VERSION+'</Version>');
    List.Add(#9#9'<Date>'+DateTimeToStr(Date)+'</Date>');
    List.Add(#9#9'<Title>'+UTF8Encode(FName)+'</Title>');
    List.Add(#9#9'<FileSource>'+UTF8Encode(SourceDataFileName)+'</FileSource>');
    List.Add(#9#9'<FileReport>'+UTF8Encode(HtmlReportFileName)+'</FileReport>');
    List.Add(#9'</CommonData>');
    List.Add(''); 
...............
...............
    List.Add('');
    List.Add('</Data>');

    List.SaveToFile(FileName);
    List.Clear;                                                         
end;
Аватара пользователя
vada
энтузиаст
 
Сообщения: 691
Зарегистрирован: 14.02.2006 13:43:17

Re: Генерация XML

Сообщение [KIM] » 24.04.2013 12:09:08

Спасибо, но, во первых я неправильно привел XML, надо так
Код: Выделить всё
  <group>
    <Id>cneljwnclwncvwjv</Id>
   <sort>100</sort>
   <name>Двери</name>
   <picture>pic01.jpg</picture>
    <groups>
      <group>
       <Id>hfwfcwefbcwebf</Id>
      <sort>100</sort>
      <name>Входные двери</name>
      <picture></picture>
      <groups>
          <group>
            <Id>qtweqwytqycd</Id>
           <sort>100</sort>
           <name>Бренд 1</name>
           <picture></picture>
          </group>
         <group>
             <Id>reihurevifvb</Id>
            <sort>200</sort>
            <name>Бренд 2</name>
            <picture></picture>
          </group>
        </groups>
      </group>
     <group>
       <Id>pjpjnkjnkn</Id>
      <sort>200</sort>
      <name>Межкомнатные двери</name>
      <picture></picture>
      </group>
    </groups>
  </group>


То есть получается
Код: Выделить всё
  <group>
    <Id>cneljwnclwncvwjv</Id>
   <name>Двери</name>
    <groups>
      <group>
       <Id>hfwfcwefbcwebf</Id>
      <name>Входные двери</name>
      <groups>
          <group>
            <Id>qtweqwytqycd</Id>
           <name>Бренд 1</name>
          </group>
         <group>
             <Id>reihurevifvb</Id>
            <name>Бренд 2</name>
          </group>
        </groups>
      </group>
     <group>
       <Id>pjpjnkjnkn</Id>
      <name>Межкомнатные двери</name>
      </group>
    </groups>
  </group>


Стринг лист то я заполню, это не вопрос. С логикой чёт туговато стало.
Посмотрите пожалуйста исходную таблиу, там у каждой записи указан родитель записи.
Как мне так сказать индексировать узлы XML, ну или стринг листа, по уму??
[KIM]
незнакомец
 
Сообщения: 5
Зарегистрирован: 22.03.2013 00:32:14

Re: Генерация XML

Сообщение vada » 24.04.2013 13:52:26

Ну как-то так можно.

!!!!! Исправлено т.к. накосячил !!!!!

Код: Выделить всё
program TestXML;

{$mode objfpc}{$H+}

uses
  {$IFDEF UNIX}{$IFDEF UseCThreads}
  cthreads,
  {$ENDIF}{$ENDIF}
  Classes
  { you can add units after this };

type

TRecordLine = class
public
  Idx: Integer;
  Name: String;
  Level: Integer;
  Key: String;
  Img: String;
  constructor Create(aIdx: Integer; aName: String; aLevel: Integer; aKey: String; aImg: String);
end;

TRecordsList = array of TRecordLine;

var
  I: Integer;
  R: TRecordLine;
  L: TRecordsList;
  S: String;
  F: Text;

constructor TRecordLine.Create(aIdx: Integer; aName: String; aLevel: Integer; aKey: String; aImg: String);
begin
  Idx := aIdx;
  Name := aName;
  Level := aLevel;
  Key := aKey;
  Img := aImg;
end;

{ Ну как тут вы будете стркутуру заполнять, придумаете сами }
procedure Init;
var
  J: Integer;
begin
  Assign(F, 'test.xml');
  Rewrite(F);
  SetLength(L, 5);
  J := 0;
  L[J] := TRecordLine.Create(1, 'Двери', 0, 'cneljwnclwncvwjv', 'pic01.jpg');
  j += 1;
  L[J] := TRecordLine.Create(2, 'Входные двери', 1, 'hfwfcwefbcwebf', '');
  J += 1;
  L[J] := TRecordLine.Create(3, 'Бренд 1', 2, 'qtweqwytqycd', '');
  J += 1;
  L[J] := TRecordLine.Create(4, 'Бренд 2', 2, 'reihurevifvb', '');
  J += 1;
  L[J] := TRecordLine.Create(5, 'Межкомнатные двери', 1, 'pjpjnkjnkn', '');
end;

procedure WriteRecordToXML(pS: String; pR: TRecordLine; var I: Integer);
var
  Rc: TRecordLine;
  S: String;
begin
  Rc := pR;
  repeat
    WriteLn(F,pS+'<group>');
    S := pS+#9;
    WriteLn(F,S+'<id>'+Rc.Key+'</id>');
    WriteLn(F,S+'<sort>100</sort>');
    WriteLn(F,S+'<name>'+Rc.Name+'</name>');
    WriteLn(F,S+'<picture>'+Rc.Img+'</picture>');
    Inc(I);
    if (I < Length(L))
    then begin
      if (L[I].Level > Rc.Level)
      then begin
         WriteRecordToXML(S, L[I], I);
      end
      else if (L[I].Level < Rc.Level)
      then begin
        WriteLn(F,pS+'</group>');
        Exit;
      end
      else Rc := L[I];
    end;
    WriteLn(F,pS+'</group>');
  until (I >= Length(L));
end;

procedure Run;
begin
  I := 0;
  S := '';
  R := L[I];
  //
  WriteLn(F, '<?xml version="1.0" encoding="utf-8" ?>');
  WriteRecordToXML(S, R, I);
end;

procedure Done;
var
  I: Integer;
begin
  SetLength(L, 0);
  Flush(F);
  Close(F);
end;


begin
  Init;
  Run;
  Done;
end.


Вот что получается

Код: Выделить всё
<?xml version="1.0" encoding="utf-8" ?>
<group>
   <id>cneljwnclwncvwjv</id>
   <sort>100</sort>
   <name>Двери</name>
   <picture>pic01.jpg</picture>
   <group>
      <id>hfwfcwefbcwebf</id>
      <sort>100</sort>
      <name>Входные двери</name>
      <picture></picture>
      <group>
         <id>qtweqwytqycd</id>
         <sort>100</sort>
         <name>Бренд 1</name>
         <picture></picture>
      </group>
      <group>
         <id>reihurevifvb</id>
         <sort>100</sort>
         <name>Бренд 2</name>
         <picture></picture>
      </group>
   </group>
   <group>
      <id>hfwfcwefbcwebf</id>
      <sort>100</sort>
      <name>Входные двери</name>
      <picture></picture>
   </group>
</group>
Аватара пользователя
vada
энтузиаст
 
Сообщения: 691
Зарегистрирован: 14.02.2006 13:43:17

Re: Генерация XML

Сообщение SeZuka » 24.04.2013 15:52:07

Что за говнокод? Зачем тут классы? А кто память будет освобождать после их использования?
Переменную зачем-то завели, но забыли зачем?
Код: Выделить всё
procedure Done;
var
  I: Integer;
begin
  SetLength(L, 0);
  Flush(F);
  Close(F);
end;

Видимо должно было быть так:
Код: Выделить всё
procedure Done;
var
  I: Integer;
begin
  for I := 0 to Length(L) - 1 do L[I].Free;
  SetLength(L, 0);
  Flush(F);
  Close(F);
end;

И Parent_N у автора темы это вовсе не ваш Level, это ссылка на N родителя. Т.е. если продолжить к примеру:
Код: Выделить всё
N   Name                           Parent_N         id

1   Двери                          0                cneljwnclwncvwjv
2   Входные двери                  1                hfwfcwefbcwebf
3   Бренд 1                        2                qtweqwytqycd
4   Бренд 2                        2                reihurevifvb
5   Межкомнатные двери             1                pjpjnkjnkn
6   Марка 1                        4                iohiuhui
7   Марка 2                        4                buguufuf
8   Марка 1                        3                dioooidjh
9   Бренд 3                        2                hgorehgrth

Что у вас будет на выходе?
SeZuka
постоялец
 
Сообщения: 209
Зарегистрирован: 05.09.2012 14:58:05

Re: Генерация XML

Сообщение vada » 24.04.2013 18:14:21

Ну и?...
Долго вселенная будет замерев на одной ноге стоять в ожидании гениального?
:D
Аватара пользователя
vada
энтузиаст
 
Сообщения: 691
Зарегистрирован: 14.02.2006 13:43:17

Re: Генерация XML

Сообщение SeZuka » 24.04.2013 19:19:56

Так полагаю, что вы ждете от меня готового решения. Но у меня сейчас нет ни времени ни желания писать за кого-то код.
Вопрос к автору, для чего создается этот XML и его формат обязательно должен быть таким как привели?
Если формат обязательно должен быть таким, тогда немного переделанный код vada:
Код: Выделить всё
program TestXML;

{$mode objfpc}{$H+}

uses
  {$IFDEF UNIX}{$IFDEF UseCThreads}
  cthreads,
  {$ENDIF}{$ENDIF}
  Classes
  { you can add units after this };

type

TRecordLine = class
public
  Idx: Integer;
  Name: String;
  Parent: Integer;
  Key: String;
  Img: String;
  constructor Create(aIdx: Integer; aName: String; aParent: Integer; aKey: String; aImg: String);
end;

TRecordsList = array of TRecordLine;

var
  L: TRecordsList;
  F: Text;

constructor TRecordLine.Create(aIdx: Integer; aName: String; aParent: Integer; aKey: String; aImg: String);
begin
  Idx := aIdx;
  Name := aName;
  Parent := aParent;
  Key := aKey;
  Img := aImg;
end;

{ Ну как тут вы будете стркутуру заполнять, придумаете сами }
procedure Init;
var
  J: Integer;
begin
  Assign(F, 'test.xml');
  Rewrite(F);
  SetLength(L, 9);
  J := 0;
  L[J] := TRecordLine.Create(1, 'Двери', 0, 'cneljwnclwncvwjv', 'pic01.jpg');
  j += 1;
  L[J] := TRecordLine.Create(2, 'Входные двери', 1, 'hfwfcwefbcwebf', '');
  J += 1;
  L[J] := TRecordLine.Create(3, 'Бренд 1', 2, 'qtweqwytqycd', '');
  J += 1;
  L[J] := TRecordLine.Create(4, 'Бренд 2', 2, 'reihurevifvb', '');
  J += 1;
  L[J] := TRecordLine.Create(5, 'Межкомнатные двери', 1, 'pjpjnkjnkn', '');
  J += 1;
  L[J] := TRecordLine.Create(6, 'Марка 1', 4, 'iohiuhui', '');
  J += 1;
  L[J] := TRecordLine.Create(7, 'Марка 2', 4, 'buguufuf', '');
  J += 1;
  L[J] := TRecordLine.Create(8, 'Марка 1', 3, 'dioooidjh', '');
  J += 1;
  L[J] := TRecordLine.Create(9, 'Бренд 3', 2, 'hgorehgrth', '');
end;

procedure WriteRecordToXML(pS: String; Parent: Integer);
var
  I: Integer;
  Rc: TRecordLine;
  S: String;
begin
  for I := 0 to Length(L) - 1 do begin
    Rc := L[I];
    if Rc.Parent <> Parent then Continue;
    WriteLn(F,pS+'<group>');
    S := pS+#9;
    WriteLn(F,S+'<id>'+Rc.Key+'</id>');
    WriteLn(F,S+'<sort>100</sort>');
    WriteLn(F,S+'<name>'+Rc.Name+'</name>');
    WriteLn(F,S+'<picture>'+Rc.Img+'</picture>');
    if Rc.Idx <> Rc.Parent then WriteRecordToXML(S, Rc.Idx);
    WriteLn(F,pS+'</group>');
  end;
end;

procedure Run;
begin
  //
  WriteLn(F, '<?xml version="1.0" encoding="utf-8" ?>');
  WriteRecordToXML('', 0);
end;

procedure Done;
var
  I: Integer;
begin
  for I := 0 to Length(L) - 1 do L[I].Free;
  SetLength(L, 0);
  Flush(F);
  Close(F);
end;


begin
  Init;
  Run;
  Done;
end.

Для
Код: Выделить всё
N   Name                           Parent_N         id

1   Двери                          0                cneljwnclwncvwjv
2   Входные двери                  1                hfwfcwefbcwebf
3   Бренд 1                        2                qtweqwytqycd
4   Бренд 2                        2                reihurevifvb
5   Межкомнатные двери             1                pjpjnkjnkn
6   Марка 1                        4                iohiuhui
7   Марка 2                        4                buguufuf
8   Марка 1                        3                dioooidjh
9   Бренд 3                        2                hgorehgrth

вывод будет таким:
Код: Выделить всё
<?xml version="1.0" encoding="utf-8" ?>
<group>
   <id>cneljwnclwncvwjv</id>
   <sort>100</sort>
   <name>Двери</name>
   <picture>pic01.jpg</picture>
   <group>
      <id>hfwfcwefbcwebf</id>
      <sort>100</sort>
      <name>Входные двери</name>
      <picture></picture>
      <group>
         <id>qtweqwytqycd</id>
         <sort>100</sort>
         <name>Бренд 1</name>
         <picture></picture>
         <group>
            <id>dioooidjh</id>
            <sort>100</sort>
            <name>Марка 1</name>
            <picture></picture>
         </group>
      </group>
      <group>
         <id>reihurevifvb</id>
         <sort>100</sort>
         <name>Бренд 2</name>
         <picture></picture>
         <group>
            <id>iohiuhui</id>
            <sort>100</sort>
            <name>Марка 1</name>
            <picture></picture>
         </group>
         <group>
            <id>buguufuf</id>
            <sort>100</sort>
            <name>Марка 2</name>
            <picture></picture>
         </group>
      </group>
      <group>
         <id>hgorehgrth</id>
         <sort>100</sort>
         <name>Бренд 3</name>
         <picture></picture>
      </group>
   </group>
   <group>
      <id>pjpjnkjnkn</id>
      <sort>100</sort>
      <name>Межкомнатные двери</name>
      <picture></picture>
   </group>
</group>


Добавлено спустя 12 минут 6 секунд:
Ну а вот все тоже самое, только без классов:
Код: Выделить всё
program TestXML;

{$mode objfpc}{$H+}

type

TRecordLine = record
  Idx: Integer;
  Name: String;
  Parent: Integer;
  Key: String;
  Img: String;
end;

TRecordsList = array of TRecordLine;

var
  L: TRecordsList;
  F: Text;

procedure SetRecordLine(I: Integer; aIdx: Integer; aName: String; aParent: Integer; aKey: String; aImg: String);
begin
  with L[I] do begin
    Idx := aIdx;
    Name := aName;
    Parent := aParent;
    Key := aKey;
    Img := aImg;
  end;
end;

{ Ну как тут вы будете стркутуру заполнять, придумаете сами }
procedure Init;
var
  J: Integer;
begin
  Assign(F, 'test.xml');
  Rewrite(F);
  SetLength(L, 9);
  J := 0;
  SetRecordLine(J, 1, 'Двери', 0, 'cneljwnclwncvwjv', 'pic01.jpg');
  j += 1;
  SetRecordLine(J, 2, 'Входные двери', 1, 'hfwfcwefbcwebf', '');
  J += 1;
  SetRecordLine(J, 3, 'Бренд 1', 2, 'qtweqwytqycd', '');
  J += 1;
  SetRecordLine(J, 4, 'Бренд 2', 2, 'reihurevifvb', '');
  J += 1;
  SetRecordLine(J, 5, 'Межкомнатные двери', 1, 'pjpjnkjnkn', '');
  J += 1;
  SetRecordLine(J, 6, 'Марка 1', 4, 'iohiuhui', '');
  J += 1;
  SetRecordLine(J, 7, 'Марка 2', 4, 'buguufuf', '');
  J += 1;
  SetRecordLine(J, 8, 'Марка 1', 3, 'dioooidjh', '');
  J += 1;
  SetRecordLine(J, 9, 'Бренд 3', 2, 'hgorehgrth', '');
end;

procedure WriteRecordToXML(pS: String; Parent: Integer);
var
  I: Integer;
  Rc: TRecordLine;
  S: String;
begin
  for I := 0 to Length(L) - 1 do begin
    Rc := L[I];
    if Rc.Parent <> Parent then Continue;
    WriteLn(F,pS+'<group>');
    S := pS+#9;
    WriteLn(F,S+'<id>'+Rc.Key+'</id>');
    WriteLn(F,S+'<sort>100</sort>');
    WriteLn(F,S+'<name>'+Rc.Name+'</name>');
    WriteLn(F,S+'<picture>'+Rc.Img+'</picture>');
    if Rc.Idx <> Rc.Parent then WriteRecordToXML(S, Rc.Idx);
    WriteLn(F,pS+'</group>');
  end;
end;

procedure Run;
begin
  //
  WriteLn(F, '<?xml version="1.0" encoding="utf-8" ?>');
  WriteRecordToXML('', 0);
end;

procedure Done;
begin
  Flush(F);
  Close(F);
end;


begin
  Init;
  Run;
  Done;
end.

И в итоге скомпилированный екзешник меньше 100кб.

Добавлено спустя 8 минут:
Но как я сказал, времени и желания делать чужую работу у меня особо нету, поэтому это тоже говнокод на скорую руку, для больших входных объемов данных переделывайте алгоритм, иначе будет неимоверно тормозить.
SeZuka
постоялец
 
Сообщения: 209
Зарегистрирован: 05.09.2012 14:58:05

Re: Генерация XML

Сообщение [KIM] » 25.04.2013 03:13:47

Спасибо огромное!!! SeZuka я и не просил делать мою работу))) По поводу
И Parent_N у автора темы это вовсе не ваш Level, это ссылка на N родителя. Т.е. если продолжить к примеру:
чётко заметил, это и было основным ступором.
Еще раз спасибо vada и SeZuka
[KIM]
незнакомец
 
Сообщения: 5
Зарегистрирован: 22.03.2013 00:32:14

Re: Генерация XML

Сообщение vada » 25.04.2013 11:33:47

SeZuka писал(а):Но у меня сейчас нет ни времени ни желания писать за кого-то код.

Понятно. ... не мешки ворочить.
SeZuka писал(а):тогда немного переделанный код vada:

Мария Ивановна! А SeZuka списывает! Чужое щастье ворует!
=:D
To SeZuka у меня тоже времени не мешки, но я нашел несколько минут чтоб показать мою идею решения задачи автора. Если что-то и коряво и не до конца сделано, этой задачи и не ставилось.
Аватара пользователя
vada
энтузиаст
 
Сообщения: 691
Зарегистрирован: 14.02.2006 13:43:17


Вернуться в Lazarus

Кто сейчас на конференции

Сейчас этот форум просматривают: нет зарегистрированных пользователей и гости: 241

Рейтинг@Mail.ru