Odczyt pliku XML i zapis poszczególnych node'ów do bazy

Odczyt pliku XML i zapis poszczególnych node'ów do bazy
BU
  • Rejestracja:ponad 22 lata
  • Ostatnio:minuta
  • Postów:297
0

Witam,
Potrzebuję pomocy w napisaniu czegoś na kształt parsera pliku XML. Przyznam szczerze, że nie wiem jak się za to zabrać. Potrzebuję odczytywać węzeł po węźle i zapisywać je do tabeli w bazie danych. childy, muszą wiązać się do parentów. Podpowie ktoś, jak to zacząć?


Pozdrawiam
Buster
MY
  • Rejestracja:prawie 10 lat
  • Ostatnio:5 minut
  • Postów:1083
0

Robiłem coś podobnego. Jednak ja wczytywałem względnie małe dokumenty. Jedyne co mi było potrzebne, to komponent https://docwiki.embarcadero.com/Libraries/Athens/en/Xml.XMLDoc.TXMLDocument Po załadowaniu do komponentu pliku parsuje on i masz dostępne całe drzewo w postaci Node'ów https://docwiki.embarcadero.com/Libraries/Athens/en/Xml.XMLDoc.TXMLDocument.Node i każdy taki węzeł ma listę węzłów podrzędnych. Możesz przejść po wszystkich w głąb i dostaniesz się do każdego elementu.

Tylko przy kilku megabajtowych plikach wczytywanie może trochę (kilka sekund) trwać.

BU
  • Rejestracja:ponad 22 lata
  • Ostatnio:minuta
  • Postów:297
0

Wiesz. Tyle to ja wiem. Sam komponent TXMLDocument to ja znam. Chodzi o sam fakt odczytania poszczególnych węzłów i ich rodziców. Ale nie wartości, tylko nazw. A potem, żeby zapisywały się te nazwy węzłów do tabeli w bazie z odpowiednimi powiązaniami między sobą. Trzeba zacząć od tego, że aplikacja ma wczytywać plik, analizować jego strukturę, sprawdzić konkretną wartość z konkretnego węzła i jeśli struktura przypisana do tej wartości już istnieje w bazie, to będzie importować dane. A jeśli nie, to ma się zapisać kolejna struktura. Problemem jest to, że nie wiem jaki to plik. Wszystko ma robić praktycznie aplikacja. Rekurencja?
Żeby uściślić, to chodzi o to, jak zrobić rozpoznawanie ilości zagnieżdżeń we wczytanym pliku XML?


Pozdrawiam
Buster
edytowany 1x, ostatnio: Buster
GS
  • Rejestracja:ponad 14 lat
  • Ostatnio:około 2 godziny
1

Żeby uściślić, to chodzi o to, jak zrobić rozpoznawanie ilości zagnieżdżeń we wczytanym pliku XML?

Aby zapisać XML do tabeli taka informacja nie jest Ci zupełnie potrzebna
Później postaram się wrzucić jakiś przykład

edytowany 1x, ostatnio: grzegorz_so
GS
  • Rejestracja:ponad 14 lat
  • Ostatnio:około 2 godziny
2

Przykład załadowania XML'a do datasetu.
Myślę że z zapisem do bazy dasz sobie radę.
Przechwytywanie.JPGxmlToDataset.zip

Kopiuj
unit Unit4;

interface

uses
  Winapi.Windows, Winapi.Messages, System.SysUtils, System.Variants, System.Classes, Vcl.Graphics, math, strutils,
  Vcl.Controls, Vcl.Forms, Vcl.Dialogs, generics.Collections, Vcl.ComCtrls, Data.DBXFirebird, Data.DB, Data.SqlExpr, Vcl.StdCtrls,
  Xmldoc, xmlIntf, Vcl.Grids, Vcl.DBGrids, Datasnap.DBClient, midaslib;

type
  TForm4 = class(TForm)
    btnLoadFromXml: TButton;
    ClientDataSet1: TClientDataSet;
    DataSource1: TDataSource;
    DBGrid1: TDBGrid;
    procedure btnLoadFromXmlClick(Sender: TObject);
    procedure FormCreate(Sender: TObject);
  public
    { Public declarations }
    Xmldoc: Ixmldocument;
    procedure loadFromXml;
  end;

var
  Form4: TForm4;
  id: integer;

const
  xmlTxt = //
   '<gridfiltr>' + #13 + //
    '<gridname>GRID_MAG_V2_</gridname>' + #13 + //
    '<filtername></filtername>' + #13 + //
    '<hardfilters>' + #13 + //
    '</hardfilters>' + #13 + //
    '<predefinedfilters>' + #13 + //
    '<simplefilter>' + #13 + //
    '<active>1</active>' + #13 + //
    '<or>1</or>' + #13 + //
    '<filters>' + #13 + //
    '<filtr>' + #13 + //
    '	<column></column>' + #13 + //
    '	<value></value>' + #13 + //
    '	<condition></condition>' + #13 + //
    '	<id>0</id>' + #13 + //
    '	<active>1</active>' + #13 + //
    '	<visible>1</visible>' + #13 + //
    '</filtr>' + #13 + //
    '<filtr>' + #13 + //
    '	<column></column>' + #13 + //
    '	<value></value>' + #13 + //
    '	<condition></condition>' + #13 + //
    '	<id>1</id>' + #13 + //
    '	<active>0</active>' + #13 + //
    '	<visible>1</visible>' + #13 + //
    '</filtr>' + #13 + //
    '<filtr>' + #13 + //
    '	<column></column>' + #13 + //
    '	<value></value>' + #13 + //
    '	<condition></condition>' + #13 + //
    '	<id>2</id>' + #13 + //
    '	<active>0</active>' + #13 + //
    '	<visible>1</visible>' + #13 + //
    '</filtr>' + #13 + //
    '<filtr>' + #13 + //
    '	<column></column>' + #13 + //
    '	<value></value>' + #13 + //
    '	<condition></condition>' + #13 + //
    '	<id>3</id>' + #13 + //
    '	<active>0</active>' + #13 + //
    '	<visible>1</visible>' + #13 + //
    '</filtr>' + #13 + //
    '<filtr>' + #13 + //
    '	<column></column>' + #13 + //
    '	<value></value>' + #13 + //
    '	<condition></condition>' + #13 + //
    '	<id>4</id>' + #13 + //
    '	<active>0</active>' + #13 + //
    '	<visible>1</visible>' + #13 + //
    '</filtr>' + #13 + //
    '</filters>' + #13 + //
    '</simplefilter>' + #13 + //
    '</predefinedfilters>' + #13 + //
    '<browsefilters>' + #13 + //
    '<column></column>' + #13 + //
    '<filters>' + #13 + //
    '</filters>' + #13 + //
    '</browsefilters>' + #13 + //
    '<softfilters>' + #13 + //
    '<complexfilter>' + #13 + //
    '<simplefilter>' + #13 + //
    '<active>0</active>' + #13 + //
    '<or>1</or>' + #13 + //
    '<filters>' + #13 + //
    '<filtr>' + #13 + //
    '	<column>STAN</column>' + #13 + //
    '	<value>0</value>' + #13 + //
    '	<condition>=</condition>' + #13 + //
    '	<id>0</id>' + #13 + //
    '	<active>0</active>' + #13 + //
    '	<visible>1</visible>' + #13 + //
    '</filtr>' + #13 + //
    '</filters>' + #13 + //
    '</simplefilter>' + #13 + //
    '</complexfilter>' + #13 + //
    '</softfilters></gridfiltr>' + #13;

implementation

{$R *.dfm}

{ TelementsList }
function idGen: integer;
begin
  inc(id);
  result := id;
end;

{ TForm4 }

procedure addNodeToDataset(aDataset: Tdataset; aNode: Ixmlnode; aParentId: int64);
var
  newId: int64;
  i: integer;
begin
  newId := idGen;
  aDataset.Append;
  aDataset.fieldbyname('id').asinteger := newId;
  aDataset.fieldbyname('node_name').asstring := aNode.nodename;
  if aNode.IsTextElement then
    aDataset.fieldbyname('node_value').asstring := aNode.text;
  aDataset.fieldbyname('parent_id').asinteger := aParentId;
  aDataset.post;
  for i := 0 to aNode.childnodes.count - 1 do
    if aNode.childnodes[i].NodeType = tnodetype.ntElement then
      addNodeToDataset(aDataset, aNode.childnodes[i], newId);
end;

procedure TForm4.btnLoadFromXmlClick(Sender: TObject);
begin
  self.loadFromXml;
end;

procedure TForm4.FormCreate(Sender: TObject);
begin
  self.Xmldoc := Txmldocument.Create(nil);
  self.ClientDataSet1.fielddefs.add('id', ftlargeint);
  self.ClientDataSet1.fielddefs.add('parent_id', ftlargeint);
  self.ClientDataSet1.fielddefs.add('node_name', ftstring, 50);
  self.ClientDataSet1.fielddefs.add('node_value', ftstring, 50);
  self.ClientDataSet1.createdataset;
end;

procedure TForm4.loadFromXml;
begin
  begin
    self.ClientDataSet1.disablecontrols;
    self.ClientDataSet1.open;
    self.ClientDataSet1.emptydataset;
    self.Xmldoc.XML.text := xmlTxt;
    self.Xmldoc.Active := true;
    addNodeToDataset(self.ClientDataSet1, self.Xmldoc.DocumentElement, 0);
    self.ClientDataSet1.enablecontrols;
  end;
end;

initialization

id := 0;

end.
edytowany 2x, ostatnio: grzegorz_so
KA
Od Delphi 12 można deklarować Multiline String
GS
KA
Chyba że tak, bo właśnie dziwiłem się dlaczego nie użyłeś przydatnego tutaj usprawnienia. Myślałem że nie wiedziałeś / zapomniałeś o tej możliwości.
GS
@kAzek: tylko dla potrzeb tego przykładu treść XML'a umieściłem w stałej. MultiLine String to fajna rzecz
MY
  • Rejestracja:prawie 10 lat
  • Ostatnio:5 minut
  • Postów:1083
0

Dokładnie, nie potrzeba tutaj ilości zagnieżdżeń. Po prostu trzeba by rekurencyjnie dodawać węzły i odpowiednio stworzyć drzewiastą strukturę tabeli w bazie danych.

Zarejestruj się i dołącz do największej społeczności programistów w Polsce.

Otrzymaj wsparcie, dziel się wiedzą i rozwijaj swoje umiejętności z najlepszymi.