XML Tutorial/hu

From Lazarus wiki
Jump to navigationJump to search

Deutsch (de) English (en) español (es) français (fr) magyar (hu) Bahasa Indonesia (id) italiano (it) 日本語 (ja) 한국어 (ko) português (pt) русский (ru) 中文(中国大陆) (zh_CN)

XML Tananyag


Bevezetés

A Kiterjeszthető jelölőnyelv (Extensible Markup Language) egy, a W3C által ajánlott nyelv, amely azért jött létre, hogy információcserét tegyen lehetővé különböző rendszerek között. Ez egy szövegalapú módszere az információ tárolásnak. A modern adatcsere nyelvek, mint az XHTML, úgy, mint a legtöbb WebServices technológia, XML alapú.

Jelenleg, van egy unit-készlet, amely támogatja az XML használatát Free Pascal-lal. Ezek a unit-ok a következők: "XMLRead", "XMLWrite" és a "DOM". Ezek részei a szabad komponenstárnak (FCL). Az FCL már szerepel a Lazarus unit keresési útvonalai között, tehát neked már csak annyi a dolgod, hogy ezeket a unit-okat hozzáadd a uses szekciódhoz az XML támogatás használatához. Az FCL nincs dokumentálva jelenleg (2005. októbere), tehát ennek a segédletnek az a célja, hogy bemutassa az XML használatát ezekkel a unit-okkal.

Az XML DOM (Dokumentum Objektum Modell), szabványosított objektumok gyűjteménye, amely hasonló felületet nyújt az XML használatához különféle nyelveken és rendszereken. A szabvány csak a metódusokat, tulajdonságokat és az objektum egyéb elemeit határozza meg, szabadon hagyva az implementáció lehetőségét a különböző nyelveknek. Az FCL jelenleg a teljes XML DOM 1.0-t támogatja.

Példák

Lejjebb találsz egy listát az XML adatok kezelésével kapcsolatos példákról, fokozatosan növekvő bonyolultsággal.

Szövegelem olvasása

Delphi programozóknak: Vedd figyelembe, hogy amikor egy TXMLDocument-tel dolgozunk, az elemen belüli szöveg, egy különálló szövegelemként van kezelve. Ennek eredményeként: egy elem szövegét úgy tudod elérni, ha különálló elemként tekinted. Másik megoldás: a TextContent tulajdonság használható, hogy egy adott elem összes szövegtartalmát, összefűzve megszerezd.

A ReadXMLFile függvény mindig létrehoz egy új TXMLDocument-et, tehát neked nem kell előzőleg kézzel létrehoznod. Ellenben, ne felejtsd el felszabadítani a dokumentumot a Free meghívásával, amikor kész vagy.

Például, vegyük a következő XML-t:

 <?xml version="1.0"?>
 <request>
   <request_type>PUT_FILE</request_type>
   <username>123</username>
   <password>abc</password>
 </request>

A következő példakód bemutatja mind a helyes, mind a helytelen módját egy szövegelem értékének megszerzéséhez:

 var
  PassNode: TDOMNode;
  Doc:      TXMLDocument;
 begin
  // XML fájl beolvasása a lemezről

  ReadXMLFile(Doc, 'c:\xmlfiles\test.xml');

  // A "password" elem beolvasása

  PassNode := Doc.DocumentElement.FindNode('password');

  // A kiválasztott elem értékének kiíratása

  WriteLn(PassNode.NodeValue); // üres lesz

  // Az elem szövege valójában egy különálló gyerek elem

  WriteLn(PassNode.FirstChild.NodeValue); // helyesen kiírja az "abc"-t

  // másképpen:

  WriteLn(PassNode.TextContent);

  // végül, felszabadítjuk a dokumentumot:

  Doc.Free;
end;

Az elemek nevének kiíratása

Egy gyors megjegyzés a DOM fában való navigáláshoz: Amikor az elemeket sorrendben kell elérned, a legjobb a FirstChild és a NextSibling tulajdonságok használata (előre való lépkedéshez), vagy a LastChild és a PreviousSibling (hátrafelé lépkedéshez). Véletlenszerű eléréshez használhatók a ChildNodes vagy a GetElementsByTagName metódusok, de ezek egy TDOMNodeList objektumot fognak létrehozni, amit szintén fel kell szabadítani. Ez eltér más DOM implementációktól, mint pl. az MSXML, mert az FCL implementáció objektum, nem pedig interfész alapú.

A következő példa bemutatja, hogy hogyan írassuk ki az elemek nevét egy TMemo-ba.

Ez a 'C:\Programok\test.xml' fájl tartalma:

 <?xml version="1.0"?>
 <images directory="mydir">
  <imageNode URL="graphic.jpg" title="">
    <Peca DestinoX="0" DestinoY="0">Pecacastelo.jpg1.swf</Peca>
    <Peca DestinoX="0" DestinoY="86">Pecacastelo.jpg2.swf</Peca>
  </imageNode>
 </images>

És itt a Pascal kód a feladat végrehajtásához:

 var
   Document: TXMLDocument;
   Child: TDOMNode;
   j: Integer;
 begin
   ReadXMLFile(Document, 'C:\Programok\test.xml');
   Memo.Lines.Clear;

   // FirstChild és NextSibling használatával:

   Child := Document.DocumentElement.FirstChild;
   while Assigned(Child) do
   begin
     Memo.Lines.Add(Child.NodeName + ' ' + Child.Attributes.Item[0].NodeValue);

     // ChildNodes metódus használatával:

     with Child.ChildNodes do
     try
       for j := 0 to (Count - 1) do
         Memo.Lines.Add(Item[j].NodeName + ' ' + Item[j].FirstChild.NodeValue);
     finally
       Free;
     end;
     Child := Child.NextSibling;
   end;
   Document.Free;
 end;

Ez lesz a kimenet:

imageNode graphic.jpg
Peca Pecacastelo.jpg1.swf
Peca Pecacastelo.jpg1.swf

Fastruktúra feltöltése XML-lel

Egy elterjedt módja az XML fájlok használatának, az, hogy a tartalmukat egy fastruktúrában használjuk fel. A TTreeView komponens a "Common Controls" fülön található a Lazarus-ban.

A lenti függvény egy előzőleg betöltött vagy a kódban generált XML dokumentum alapján feltölt egy fastruktúrát a tartalmával. Minden egyes elem megnevezése az első attribútumának tartalma lesz.

procedure TForm1.XML2Tree(tree: TTreeView; XMLDoc: TXMLDocument);
var
  iNode: TDOMNode;

  procedure ProcessNode(Node: TDOMNode; TreeNode: TTreeNode);
  var
    cNode: TDOMNode;
    s: string;
  begin
    if Node = nil then Exit; // Kilépés, ha egy ág végére értünk
    
    // Elem hozzáadása a fához
    if Node.HasAttributes and (Node.Attributes.Length>0) then
      s:=Node.Attributes[0].NodeValue
    else
      s:=''; 
    TreeNode := tree.Items.AddChild(TreeNode, s);

    // Ugrás az első gyerek elemhez
    cNode := Node.FirstChild;

    // Gyerek elemek feldolgozása
    while cNode <> nil do
    begin
      ProcessNode(cNode, TreeNode);
      cNode := cNode.NextSibling;
    end;
  end;
    
begin
  iNode := XMLDoc.DocumentElement.FirstChild;
  while iNode <> nil do
  begin
    ProcessNode(iNode, nil); // Rekurzívan
    iNode := iNode.NextSibling;
  end;
end;

XML dokumentum módosítása

Az első dolog, amit meg kell jegyezni, az hogy a TDOMDocument a "handle" a DOM-hoz. Úgy jöhet létre ennek az osztálynak példánya, hogy saját kezűleg létrehozod, vagy egy XML dokumentumot betöltesz.

Másfelől, az elemek nem hozhatók létreh úgy, mint egy normál objektum. A TDOMDocument metódusait KELL használod, hogy létrehozd őket, és később más metódusokat, hogy a megfelelő helyre tehesd őket a szerkezetben. Ez azért van, mert az elemeket egy meghatározott dokumentumnak kell birtokolnia a DOM-ban.

Lejjebb található a TDOMDocument néhány általános metódusa:

   function CreateElement(const tagName: DOMString): TDOMElement; virtual;
   function CreateTextNode(const data: DOMString): TDOMText;
   function CreateCDATASection(const data: DOMString): TDOMCDATASection;
     virtual;
   function CreateAttribute(const name: DOMString): TDOMAttr; virtual;

És itt egy példa, ami megkeresi a TTreeView-ben kijelölt elemet és elhelyez egy gyerek elemet abba az XML dokumentumba, amelyet reprezentál. A fastruktúrát előtte fel kell tölteni egy XML fájl tartalmával a XML2Tree function használatával.

procedure TForm1.actAddChildNode(Sender: TObject);
var
  position: Integer;
  NovoNo: TDomNode;
begin
  {*******************************************************************
  *  Megkeresi a kijelölt elemet
  *******************************************************************}
  if TreeView1.Selected = nil then Exit;

  if TreeView1.Selected.Level = 0 then
  begin
    position := TreeView1.Selected.Index;

    NovoNo := XMLDoc.CreateElement('item');
    TDOMElement(NovoNo).SetAttribute('nome', 'Item');
    TDOMElement(NovoNo).SetAttribute('arquivo', 'Arquivo');
    with XMLDoc.DocumentElement.ChildNodes do
    begin
      Item[position].AppendChild(NovoNo);
      Free;
    end;

    {*******************************************************************
    *  A fastruktúra frissítése
    *******************************************************************}
    TreeView1.Items.Clear;
    XML2Tree(TreeView1, XMLDoc);
  end
  else if TreeView1.Selected.Level >= 1 then
  begin
    {*******************************************************************
    *  Ez a függvény a fának csak az első szintjén működik,
    *  de egyszerűen módosítható úgy, hogy bármelyiken működjön
    *******************************************************************}
  end;
end;

TXMLDocument létrehozása string-ből

Adott egy XML fájl a MyXmlString-ben. A következő kód létrehozza a DOM-ját:

Var
  S : TStringStream;
  XML : TXMLDocument;

begin
  S:= TStringStream.Create(MyXMLString);
  Try
    S.Position:=0;
    XML:=Nil;
    ReadXMLFile(XML,S); // Teljes XML dokumentum
    // Másképpen:
    ReadXMLFragment(AParentNode,S); // Csak az XML töredék beolvasása.
  Finally
    S.Free;
  end;
end;

Dokumentum érvényesítése

2007. márciusa óta, a DTD érvényesítési képesség lett hozzáadva az FCL XML feldogozóhoz. Az érvényesítés ellenőrzi a dokumentum logikai felépítését az előre meghatározott szabályoknak alapján (ez a Document Type Definition /DTD/).

Itt egy példa DTD-vel ellátott XML dokumentumra:

  <?xml version='1.0'?>
  <!DOCTYPE root [
  <!ELEMENT root (child)+ >
  <!ELEMENT child (#PCDATA)>
  ]>
  <root>
    <child>Ez az első gyerek.</child>
    <child>Ez a második gyerek.</child>
  </root>

Ez a DTD meghatározza, hogy a 'root' elemnek egy vagy több 'child' elemének kell lennie, és hogy a 'child' elemek csak karakteres adatot tartalmazhatnak. Ha a feldolgozó eltérést érzékel ehhez képest, jelenteni fogja.

Egy ilyen dokumentum beolvasása jóval bonyolultabb. Vegyük azt, hogy XML adatunk van egy TStream objektumban:

procedure TMyObject.DOMFromStream(AStream: TStream);
var
  Parser: TDOMParser;
  Src: TXMLInputSource;
  TheDoc: TXMLDocument;
begin
  // feldolgozó objektum létrehozása

  Parser := TDOMParser.Create;

  // és a bemeneti forrás

  Src := TXMLInputSource.Create(AStream);

  // kérünk érvényesítést
 
  Parser.Options.Validate := True;

  // hibakezelő hozzárendelése, ami figyeli a jelentéseket

  Parser.OnError := @ErrorHandler;

  // most jöhet a feldolgozás

  Parser.Parse(Src, TheDoc);

  // ...és most takarítás

  Src.Free;
  Parser.Free;
end;

procedure TMyObject.ErrorHandler(E: EXMLReadError);
begin
  if E.Severity = esError then  // csak az érvényesítési hibák érdekelnek
    writeln(E.Message);
end;

XML fájl létrehozása

Lejjebb található egy teljes kód XML fájlba íráshoz. (Ez a DeveLazarus blog-ból lett másolva) Ne felejtsd el a DOM és az XMLWrite unit-okat a uses szekcióban!

unit Unit1;

{$mode objfpc}{$H+}

interface

uses
  Classes, SysUtils, LResources, Forms, Controls, Graphics, Dialogs, StdCtrls,
  DOM, XMLWrite;

type
  { TForm1 }
  TForm1 = class(TForm)
    Button1: TButton;
    Label1: TLabel;
    Label2: TLabel;
    procedure Button1Click(Sender: TObject);
  private
    { private declarations }
  public
    { public declarations }
  end;
  
var
  Form1: TForm1;
  
implementation

{ TForm1 }

procedure TForm1.Button1Click(Sender: TObject);
var
  xdoc: TXMLDocument;                                  // dokumentum változó
  RootNode, parentNode, nofilho: TDOMNode;                    // elemek változói
begin
  // dokumentum létrehozása
  xdoc := TXMLDocument.create;

  // gyökér elem létrehozása
  RootNode := xdoc.CreateElement('register');
  Xdoc.Appendchild(RootNode);                           // gyökér elem mentése

  // szülő elem létrehozása
  RootNode:= xdoc.DocumentElement;
  parentNode := xdoc.CreateElement('usuario');
  TDOMElement(parentNode).SetAttribute('id', '001');       // attribútumok létrehozása a szülő elemhez
  RootNode.Appendchild(parentNode);                          // szülő elem mentése

  // gyerek elem létrehozása
  parentNode := xdoc.CreateElement('nome');               
  //TDOMElement(parentNode).SetAttribute('sexo', 'M');     // attribútumok létrehozása
  nofilho := xdoc.CreateTextNode('Fernando');         // értékadás az elemhez
  parentNode.Appendchild(nofilho);                         // elem mentése
  RootNode.ChildNodes.Item[0].AppendChild(parentNode);       // gyerek elem hozzáadása a hozzátartozó szülőhöz

  // gyerek elem létrehozása
  parentNode := xdoc.CreateElement('idade');

  //TDOMElement(parentNode).SetAttribute('ano', '1976');   // attribútumok létrehozása
  nofilho := xdoc.CreateTextNode('32');               // értékadás az elemhez
  parentNode.Appendchild(nofilho);                         // elem mentése
  RootNode.ChildNodes.Item[0].AppendChild(parentNode);       // gyerek elem hozzáadása a hozzátartozó szülőhöz

  writeXMLFile(xDoc,'teste.xml');                     // kiírás XML-be
  Xdoc.free;                                          // memória felszabadítása
end;

initialization
  {$I unit1.lrs}

end.

Az eredmény a következő XML fájl:

<?xml version="1.0"?>
<register>
  <usuario id="001">
    <nome>Fernando</nome>
    <idade>32</idade>
  </usuario>
</register>

--Fernandosinesio 22:28, 24 April 2008 (CEST)fernandosinesio@gmail.com

Kódolás

Az 12582-es SVN revíziótól kezdődően, az XML olvasó alkalmas bármilyen kódolású adat feldolgozásához, külső dekódolók használatával. Lásd: XML_Decoders tovább részletekért.

Az XML szabvány alapján, az 'encoding' attribútum az XML első sorában opcionális, abban az esetben, ha a kódolás UTF-8 vagy UTF-16 (ami a BOM jelenlétéből határozható meg). A 0.9.26-os Lazarus verziótól, a TXMLDocument-nek van 'encoding' tulajdonsága, de ez tiltva van. A WriteXMLFile mindig UTF-8-at használ és nem hoz létre encoding attribútumot az XML fájl első sorában.

Külső hivatkozások