Autor Téma: Ako na XML parser?  (Přečteno 748 krát)

Online delirium

  • Nováček
  • *
  • Příspěvků: 8
  • Karma: 0
Ako na XML parser?
« kdy: 28-07-2021, 19:40:31 »
Zdravim,

potrebujem poradit, mam XML subor.

Kód: Delphi [Vybrat]
  1. unit Unit1;
  2.  
  3. interface
  4.  
  5. uses
  6.   Windows, Messages, SysUtils, Variants, Classes, Graphics, Controls, Forms,
  7.   Dialogs, XMLIntf, XMLDoc, StdCtrls;
  8.  
  9. type
  10.   TForm1 = class(TForm)
  11.     Button1: TButton;
  12.     Memo1: TMemo;
  13.     procedure Button1Click(Sender: TObject);
  14.   private
  15.     { Private declarations }
  16.   public
  17.     { Public declarations }
  18.   end;
  19.  
  20. const
  21.   TestXML = '<?xml version="1.0" encoding="UTF-8"?>' +
  22.             '<SeasonStatistics>' +
  23.             '<Team>' +
  24.             '<Player last_name="Correia Filho" player_id="168805" shirtNumber="23" first_name="Roberto Dias" position="Defender" known_name="Roberto Dias">' + // rozsirene data
  25.             '<Stat name="Games Played">1</Stat>' + // zobrazi sa
  26.             '<Stat name="Blocks">2</Stat>' + // nezobrazi sa
  27.             '<Stat name="Leftside Passes">10</Stat>' + // nezobrazi sa
  28.             '</Player>' +
  29.  
  30.             '<Player first_name="David" position="Midfielder" last_name="Cobnan" player_id="545262" shirtNumber="0" />' + // nie su rozsirene data, error: "could not convert variant of type (null) into type (string)"
  31.             '</Team>' +
  32.             '</SeasonStatistics>';
  33. var
  34.   Form1: TForm1;
  35.  
  36. implementation
  37.  
  38. {$R *.dfm}
  39.  
  40. procedure TForm1.Button1Click(Sender: TObject);
  41. var
  42.   Doc: IXMLDocument;
  43.   Root: IXMLNode;
  44.   PersonList: IXMLNodeList;
  45.   Person: IXMLNode;
  46.   i: Integer;
  47. begin
  48.   Memo1.Clear;
  49.   Doc := LoadXMLData(TestXML);
  50.   Doc.Active := True;
  51.   Root := Doc.DocumentElement;
  52.   PersonList := Root.ChildNodes['Team'].ChildNodes;
  53.   Person := PersonList.First;
  54.   while Assigned(Person) do
  55.   begin
  56. //    Memo1.Lines.Add(Person.ChildNodes['Stat name="Blocks"'].Text);  // error...
  57.  
  58.     Memo1.Lines.Add(Person.ChildValues['Stat']); // iba jeden zaznam z nodu stat... [1] !!!
  59.     Person:= Person.NextSibling;
  60.   end;
  61. end;

Ako dokopat v Delphi 7 (PRO), aby som dokazal zobrazit "Stat name="Games Played"", "Stat name="Blocks"", first_name="David" a aby to nehadzalo chybu  "could not convert variant of type (null) into type (string)"?

Dik.

Martin

Offline Stanislav Hruška

  • Padawan
  • ******
  • Příspěvků: 7303
  • Karma: 44
    • Verze Delphi: W11 + D11.3.1
Re:Ako na XML parser?
« Odpověď #1 kdy: 28-07-2021, 20:20:03 »
Ja sa v tom houby vyznám. Ale oznam jasne hovorí, že je očakávaný string a Ty tam máš null = čiže nič. V prvom rade by som sa pozrel, či sú pre Person správne hodnoty. Očakávam, že Person síce neukazuje že je nil, ale v skutočnosti je
  • nil - brať s veľkou rezervou, alebo
  • prázdny (null), alebo
  • len niektorá hodnota prázdna (null)
Test Assigned() ma už neraz "sklamal". Stačí čosi uvoľniť a nenastaviť na nil.
Win11 64b, Delphi 11.3.1, FireBird 4.01
Expert na kladenie nejasne formulovaných otázok.

Offline pepak

  • Padawan
  • ******
  • Příspěvků: 1573
  • Karma: 37
    • Pepak.net
Re:Ako na XML parser?
« Odpověď #2 kdy: 29-07-2021, 05:45:54 »
Pokud bych to chtěl mít v Delphi s plnou parádou, tak bych si na tvém místě sehnal k tomu XML ještě příslušný XSD soubor, který popisuje jeho strukturu - buď bývá součástí specifikace dat, neo jde s rizikem toho, že nebude úplně přesný, dovodit z příkladů XML. Jakmile totiž máš XSD, tak můžeš použít vestavěný XSD importer, který ti vygeneruje sadu interfaců pro zpracování tvého XML. Následně už s daty pracuješ velmi jednoduše, v tvém případě bys použil něco jako NactenySoubor.SeasonStatistics.Team.Player.Stat[2].Text.

Pokud si to chceš dělat celé sám podobně, jako jsi ukázal na začátku, tak si všimni, že element Stat se může vyskytovat několikrát zatímco ChildValues['Stat'] celkem pochopitelně vrátí jen jednu hodnotu. Pokud se chceš dostat k ostatním, nemůžeš použít ChildValues[], ale musíš proiterovat všechny elementy (ChildNodes), u každého otestovat, jestli jeho Name je 'Stat', a když ano, tak s ním něco udělat.

Co se týče té konverze, čistě by bylo kontrolkovat hodnotu null speciálně, ale dost možná si vystačíš i s jednoduchým nastavením globální proměnné SystemVariants.NullStrictConvert na false.

Offline Jan Fiala

  • Hrdina
  • ****
  • Příspěvků: 412
  • Karma: 4
    • Verze Delphi: 10.4.1
    • PSPad editor
Re:Ako na XML parser?
« Odpověď #3 kdy: 29-07-2021, 06:39:24 »
A pokud chceš jít jednoduchou cestou, použij třeba JanXMLTree, to je velmi jednoduchá, malá a rychlá implementace XML. Pak muzes pres cestu a iterace pres node <Stat name> přečíst hodnotu, kterou potřebuješ

Offline paja666

  • Mladík
  • **
  • Příspěvků: 69
  • Karma: 0
    • Verze Delphi: 11.3
Re:Ako na XML parser?
« Odpověď #4 kdy: 29-07-2021, 07:45:03 »
Jsi na špatném nodu, musíš změnit 1 řádek na (a asi nějak ošetřit případné chybějící detaily atp...)

Kód: Delphi [Vybrat]
  1.   Person := PersonList.First.ChildNodes.First;

Offline František

  • Guru
  • *****
  • Příspěvků: 893
  • Karma: 8
    • Verze Delphi: comunity 10.4.2, D2007, D11
Re:Ako na XML parser?
« Odpověď #5 kdy: 29-07-2021, 09:03:11 »
XML data binding

Offline martinnr

  • Plnoletý
  • ***
  • Příspěvků: 225
  • Karma: 2
    • Verze Delphi: 7,2009,XE7
Re:Ako na XML parser?
« Odpověď #6 kdy: 29-07-2021, 14:53:20 »
nemaju tam byt typy TXMLxxx nemiesto IXMLxxx?

Offline pepak

  • Padawan
  • ******
  • Příspěvků: 1573
  • Karma: 37
    • Pepak.net
Re:Ako na XML parser?
« Odpověď #7 kdy: 29-07-2021, 15:09:30 »
nemaju tam byt typy TXMLxxx nemiesto IXMLxxx?
Ne.

Offline Palino

  • Nováček
  • *
  • Příspěvků: 17
  • Karma: 0
    • Verze Delphi: 7, XE, Seattle
Re:Ako na XML parser?
« Odpověď #8 kdy: 10-08-2021, 09:41:56 »
skus toto ako nakopnutie (pisane popameti tak tam moze byt chybicka, ale princip by mal sediet):

Players: IXMLDOMNodeList;
Stats: IXMLDOMNodeList;
.
.
.

Players := Root.ChildNodes['Team'].childNodes;

for idx := 0 to Players.Length-1 do
begin
   value:= Players[idx].selectSingleNode('@last_name').text;

   Stats = Players[idx].childNodes;
   for idx2 = 0 to Stats.Length-1 do
      ..

end;