2009-10-07 13 views
8

Jestem nowy w delphi i teraz muszę przeczytać, aby utworzyć xml. mój kod jest następujący:Problem z budowaniem dokumentu XML za pomocą TXMLDocument

function foo.createXMLDocument(): TXMLDocument; 
var 
    res: TXMLDocument; 
    rootNode: IXMLNode; 
    sl : TStringList; 
begin 
    res := TXMLDocument.Create(nil); 
    res.Active := true; 
    rootNode := res.AddChild('label'); 
    // create string for debug purposes 
    sl := TStringList.Create; 
    sl.Assign(res.XML);// sl is empty after this assignment 
    //add more elements 
    generateDOM(rootNode); 

    Result := res; 
end; 

Problem polega na tym, że liczba węzłów podrzędnych wzrasta, ale res.XML jest pusty. Nie wspominając o tym, że reszta elementów w procedurze generateDOM najwyraźniej nic nie robi. Będę bardzo zadowolony z twojej pomocy.

+0

Byłoby dobrze, gdyby podałeś wersję Delphi używasz. Zobacz moją odpowiedź w przypadku D2007. –

Odpowiedz

12

Nota prawna: Przetestowano za pomocą D2007.

Kod rzeczywiście tworzyć XML (<label/>), jak pokazano w tym zmodyfikowanym funkcję:

function createXMLDocument(): TXMLDocument; 
var 
    res: TXMLDocument; 
    rootNode: IXMLNode; 
    sl : TStringList; 
begin 
    res := TXMLDocument.Create(nil); 
    res.Active := true; 
    rootNode := res.AddChild('label'); 
    // create string for debug purposes 
    sl := TStringList.Create; // not needed 
    sl.Assign(res.XML); // Not true: sl is empty after this assignment 
    ShowMessage(sl.text);// sl is NOT empty! 
    sl.Free;    // don't forget to free it! use try..finally.. to guarantee it! 
    //add more elements 
// generateDOM(rootNode); 
    Result := res; 
end; 

Ale to wymaga dużo uwagi:
- Ty nie potrzebujesz lokalna zmienna res, wystarczy użyć wyniku.
- Nie potrzeba dodatkowego StringList zobaczyć XML: Result.Xml.Text
- Nie zapomnij bezpłatnym StringList sl jeśli utworzyć.
- Zwrócony XmlDocument nie nadaje się do użytku poza funkcją i daje sygnał AV, jeśli spróbujesz.

Dlaczego?
To dlatego XmlDocument jest przeznaczony do stosowania jako komponent z właścicielem, lub jako interfejsu w inny sposób, aby zarządzać swoim żywotność.
Fakt, że używasz Interfejsu do przechowywania rootNode powoduje, że jest on niszczony na końcu funkcji CreateXmlDocument. A jeśli spojrzysz na kod w TXMLNode._Release, zobaczysz, że uruchamia on TXMLDocument._Release, który wywołuje Destroy, chyba że istnieje Właściciel dla XMLDocument (lub interfejsu przechowującego odnośnik do niego).
Dlatego właśnie dokument XMLDocument jest poprawny i zapełniony wewnątrz funkcji CreateXMLDocument, ale nie jest dostępny poza nim, chyba że zwrócisz interfejs lub podasz właściciela.

Zobacz alternatywne rozwiązania poniżej:

function createXMLDocumentWithOwner(AOwner: TComponent): TXMLDocument; 
var 
    rootNode: IXMLNode; 
begin 
    Assert(AOwner <> nil, 'createXMLDocumentWithOwner cannot accept a nil Owner'); 
    Result := TXMLDocument.Create(AOwner); 
    Result.Active := True; 
    rootNode := Result.AddChild('label'); 
    OutputDebugString(PChar(Result.Xml.Text)); 
    //add more elements 
// generateDOM(rootNode); 
end; 

function createXMLDocumentInterface(): IXMLDocument; 
var 
    rootNode: IXMLNode; 
begin 
    Result := TXMLDocument.Create(nil); 
    Result.Active := True; 
    rootNode := Result.AddChild('label'); 
    OutputDebugString(PChar(Result.Xml.Text)); 
    //add more elements 
// generateDOM(rootNode); 
end; 


procedure TForm7.Button1Click(Sender: TObject); 
var 
    doc: TXmlDocument; 
    doc2: IXMLDocument; 
begin 
    ReportMemoryLeaksOnShutdown := True; 

    doc := createXMLDocument; 
    // ShowMessage(doc.XML.Text); // cannot use it => AV !!!! 
    // already freed, cannot call doc.Free; 

    doc := createXMLDocumentWithOwner(self); 
    ShowMessage(doc.XML.Text); 

    doc2 := createXMLDocumentInterface; 
    ShowMessage(doc2.XML.Text); 
end; 
2

W mojej podobnej implementacji deklaruję res jako IXMLDocument zamiast TXMLDocument.

var 
    XMLDoc: IXMLDocument; 
. 
. 
    XMLDoc := TXMLDocument.Create(nil); 
    XMLDoc.Active := True; 
. 
. 
    XMLDoc.SaveToFile(Filename); 
    XMLDoc.Active := False; 
+0

Mimo że jest to poprawna rzecz podczas tworzenia wystąpienia TXmlDocument bez składnika właściciela, nie ma to znaczenia dla problemu. –

4

Delphi Help metody TXMLDocument.AddChild mówi (na dole):

Uwaga: Nie nazywaj addChild dodać dziecko do elementu dokumentu tego dokumentu. Podczas dodawania danych do dokumentu XML użyj metody AddChild elementu document lub węzła w hierarchii, który powinien być elementem nadrzędnym nowego węzła.

I to właśnie robisz dobrze? :-)

Oto artykuł wprowadzający na temat Delphi XML Document Programming i pokazuje, jak można pracować z właściwością TXMLDocument.DocumentElement zamiast z definicją zmiennej rootnode w kodzie.

+0

Wprowadzony cytat nie pokazuje, jak utworzyć nowy dokument od zera. Nie ma również strony pomocy. W jaki sposób kod w pytaniu powinien się zmienić, aby był właściwy? –

+0

w D2007 TXmlDocument.AddChild tworzy węzeł DocumentNode, jeśli jeszcze tam nie jest i wywołuje jego AddChild. Więc to nie problem. –

+0

Erwin, edytujesz swoją odpowiedź, ale nie sądzę, że skierowałeś mój komentarz. –

Powiązane problemy