XML Tutorial/hu

From Lazarus wiki
Revision as of 11:11, 24 March 2012 by Vincent (talk | contribs) (Text replace - "<xml>" to "<syntaxhighlight lang="xml">")
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:

<syntaxhighlight lang="xml">

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

</xml>

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:

<delphi>

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; </delphi>

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:

<syntaxhighlight lang="xml">

<?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>

</xml>

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

<delphi>

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;

</delphi>

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.

<delphi> 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; </delphi>

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:

<delphi>

  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;

</delphi>

É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.

<delphi> 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; </delphi>

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:

<delphi> 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; </delphi>

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:

<syntaxhighlight lang="xml">

 <?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>

</xml>

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:

<delphi> 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; </delphi>

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!

<delphi> 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. </delphi>

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

<syntaxhighlight lang="xml"> <?xml version="1.0"?> <register>

 <usuario id="001">
   <nome>Fernando</nome>
   <idade>32</idade>
 </usuario>

</register> </xml>

--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