TXMLDocument [Résolu]

sylvunix 103 Messages postés mardi 11 avril 2006Date d'inscription 4 mars 2009 Dernière intervention - 11 déc. 2006 à 13:44 - Dernière réponse : sylvunix 103 Messages postés mardi 11 avril 2006Date d'inscription 4 mars 2009 Dernière intervention
- 19 janv. 2007 à 07:23
Bonjour,

Je vous soumet un dysfonctionnement pour lequel je ne parviens pas à trouver de solution depuis plusieurs mois. Le balayage des sources et des forums ne m'a pas beaucoup aidé (j'ai trouvé un problème proche http://www.delphifr.com/infomsg_TXMLDOCUMENT-DANS-UNITE_365963.aspx mais pas solutionné).

Mon problème est le suivant : J'ai écrit une classe dans laquelle une des méthodes permet de lire un fichier xml. Pour cela je me base sur la classe TXMLDocument.

A l'exécution (méthode LoadFromFile1), j'obtiens une erreur EAccessViolation sur XMLNode.ChildNodes.Count.

Cepandant, si je déclare un objet TXMLDocument sur mon form et que je passe en paramètre (métode LoadFromFile2), tout va bien.

Il y a certainement une subtilité qui m'échappe.

Je poste un exemple simplifié qui illustre mon soucis.

Si vous avez la moindre idée, je vous serais très reconnaissant de m'en faire part ...

Merci à tous

PS : Je souhaite réaliser une classe totalement indépendante donc ma solution de contournement n'est pas acceptable.


unit MaClasse;

interface

uses
xmldom, XMLIntf, msxmldom, XMLDoc;

type
TMaClasse = class(TObject)
private
procedure Decode(XMLNode: IXMLNode);
public
procedure LoadFromFile1(Filename: String);
procedure LoadFromFile2(XMLDocument: TXMLDocument; Filename: String);
end;

implementation

uses
Dialogs, SysUtils;

procedure TMaClasse.Decode(XMLNode: IXMLNode);
begin
MessageDlg(IntToStr(XMLNode.ChildNodes.Count),mtInformation,[mbOk],0);
end;

procedure TMaClasse.LoadFromFile1(Filename: String);
var
XMLDocument: TXMLDocument;
begin
XMLDocument := TXMLDocument.Create(Filename);
XMLDocument.Active := True;
Decode(XMLDocument.ChildNodes.First);
XMLDocument.Active := False;
XMLDocument.Destroy;
end;

procedure TMaClasse.LoadFromFile2(XMLDocument: TXMLDocument; Filename: String);
begin
XMLDocument.Active := True;
XMLDocument.LoadFromFile(Filename);
Decode(XMLDocument.ChildNodes.First);
XMLDocument.Active := False;
end;

end.



unit Form;

interface

uses
Windows, Messages, SysUtils, Variants, Classes, Graphics, Controls, Forms,
Dialogs, xmldom, XMLIntf, msxmldom, XMLDoc, StdCtrls;

type
TForm1 = class(TForm)
Button1: TButton;
XMLDocument1: TXMLDocument;
Button2: TButton;
procedure Button1Click(Sender: TObject);
procedure Button2Click(Sender: TObject);
private
{ Déclarations privées }
public
{ Déclarations publiques }
end;

var
Form1: TForm1;

implementation

uses
MaClasse;

{$R *.dfm}

procedure TForm1.Button1Click(Sender: TObject);
var
MaClasse: TMaClasse;
begin
MaClasse := TMaClasse.Create;
MaClasse.LoadFromFile1('C:\Temp\Sample.xml');
MaClasse.Destroy;
end;

procedure TForm1.Button2Click(Sender: TObject);
var
MaClasse: TMaClasse;
begin
MaClasse := TMaClasse.Create;
MaClasse.LoadFromFile2(XMLDocument1,'C:\Temp\Sample.xml');
MaClasse.Destroy;
end;

end.
Afficher la suite 

Votre réponse

11 réponses

Meilleure réponse
cs_Loda 900 Messages postés vendredi 3 novembre 2000Date d'inscription 30 juillet 2009 Dernière intervention - 12 déc. 2006 à 10:23
3
Merci
salut,

j'ai eut le même problème et comme toi, j'aivais pas trouvé de solution pendant des plombes... alors j'avais poster une source. je suis un peu deçu que tu ne l'ai pas trouvée, mais la voici:
http://www.delphifr.com/codes/LIRE-ECRIRE-XML-DEPUIS-UNITE_39531.aspx

j'espère que ça t'aideras.

tiens nous au courant,
Bon code,

Merci cs_Loda 3

Avec quelques mots c'est encore mieux Ajouter un commentaire

Codes Sources a aidé 101 internautes ce mois-ci

Commenter la réponse de cs_Loda
florenth 1105 Messages postés dimanche 1 août 2004Date d'inscription 17 août 2008 Dernière intervention - 11 déc. 2006 à 16:39
0
Merci
N'aurais-tu pas oublié de spécifier le "vendeur" DOM ?
Ou alors confondu ChildNodes avec DocumentElement.ChildNodes ?

Pour le premier, il suffit de définit la propriété DOMVendor :
<hr size= "2" width="100%" /> uses
  XmlDoc, XmlDom, XmlIntf, MsXmlDom; // Ne pas en oublier !!

[...]

var
  Xml: TXMLDocument;
begin
  Xml : = TXmlDocument.Create('C:\blablabla.xml');
  try
    Xml.DOMVendor := MSXML_DOM;
    Xml.Active := True;
    { Traitement du fichier ici }
  finally
    Xml.Free;
  end;
end;
<hr size ="2" width="100%" />
Commenter la réponse de florenth
sylvunix 103 Messages postés mardi 11 avril 2006Date d'inscription 4 mars 2009 Dernière intervention - 11 déc. 2006 à 21:11
0
Merci
Merci florenth pour ta réponse.

J'ai essayé ta solution pour avoir bonne conscience mais j'avais déjà testé DOMVendor := GetDOMVendor('MSXML'); qui revient au même (du moins je pense).

Le problème que je rencontre me semble assez compliqué. Le fichier est bien lu (XML.Text contient le code xml complet) et parsé car j'arrive à lire un attribut du premier noeud.

Ensuite, dès que je souhaite naviguer dans les AttributeNodes ou ChildNodes j'ai toute la collection d'erreurs possibles : EPrivilege, TAccessViolation et TAbstractError !

Le même code avec le XMLDocument sur une form fonctionne parfaitement ...

Cela est déprimant ... Au bout de trois nouvelles heures d'investigation, je me demande s'il ne s'agirait pas d'un dysfonctionnement du composant lui-même !

Pour info, j'utilise Delphi 7.

Je suis ouvert à toute suggestion ...

:-(
Commenter la réponse de sylvunix
sylvunix 103 Messages postés mardi 11 avril 2006Date d'inscription 4 mars 2009 Dernière intervention - 12 déc. 2006 à 11:00
0
Merci
Salut Loda,

Désolé d'avoir zappé ton source. Pourtant ce n'est pas faute d'avoir cherché tu peux me croire !

Je l'ai téléchargé et je me met au boulot ...

Je te fais un compte-rendu demain ...

Merci beaucoup pour ton aide.
Commenter la réponse de sylvunix
cs_Loda 900 Messages postés vendredi 3 novembre 2000Date d'inscription 30 juillet 2009 Dernière intervention - 12 déc. 2006 à 11:24
0
Merci
j'ai pas du mettre les bon mots clès.... :(
Commenter la réponse de cs_Loda
sylvunix 103 Messages postés mardi 11 avril 2006Date d'inscription 4 mars 2009 Dernière intervention - 13 déc. 2006 à 07:47
0
Merci
Salut Loda,

Ton source m'a effectivement permi de comprendre l'origine de mon problème.

J'avais bien mis le doigt sur la différence de fonctionnement lorsque le
composant XMLDocument était créé sur une form à la conception ou à la volée dans mon unité mais j'avais incapable d'aller plus loin.

J'ai trouvé la solution dans ton source avec l'utilisation de TDataModule.

Extrait de l'aide en ligne Delphi :

"Utilisez un objet TDataModule dans une application afin de centraliser la gestion des composants non visuels. En général, ce sont des composants d'accès aux données, tels que TSQLDataSet et TSQLConnection. Les modules de données ne sont pas limités aux composants d'accès aux données, ils peuvent également contenir d'autres composants non visuels comme TTimer, TOpenDialog ou TImageList.

A la conception, un objet TDataModule propose un conteneur visuel dans lequel le développeur peut placer les composants non visuels, définir leurs propriétés et écrire leurs gestionnaires d'événements. A la conception, pour créer un nouveau module de données, choisissez Fichier|Nouveau module de données.

Dans le fichier unité du module de données, un développeur peut également définir des règles de fonctionnement appliquées à l'application."

Je joins l'adaptation de mon source exemple au cas où quelqu'un serait confronté à nouveau à ce problème (et n'aurait pas trouvé son source !)

unit MaClasse;

interface

uses
Classes, XMLIntf, XMLDoc;

type
TMaClasse = class(TObject)
private
FDataModule: TDataModule;
procedure Decode(XMLNode: IXMLNode);
public
constructor Create;
procedure LoadFromFile1(Filename: String);
procedure LoadFromFile2(XMLDocument: TXMLDocument; Filename: String);
end;

implementation

uses
Dialogs, SysUtils;

constructor TMaClasse.Create;
begin
FDataModule := TDataModule.Create(nil);
end;

procedure TMaClasse.Decode(XMLNode: IXMLNode);
begin
MessageDlg(IntToStr(XMLNode.ChildNodes.Count),mtInformation,[mbOk],0);
end;

procedure TMaClasse.LoadFromFile1(Filename: String);
var
XMLDocument: TXMLDocument;
begin
XMLDocument := TXMLDocument.Create(FDataModule);
XMLDocument.Active := True;
XMLDocument.LoadFromFile(Filename);
Decode(XMLDocument.ChildNodes.First);
XMLDocument.Active := False;
XMLDocument.Destroy;
end;

procedure TMaClasse.LoadFromFile2(XMLDocument: TXMLDocument; Filename: String);
begin
XMLDocument.Active := True;
XMLDocument.LoadFromFile(Filename);
Decode(XMLDocument.ChildNodes.First);
XMLDocument.Active := False;
end;

end.

Encore un grand merci à toi. Je ne t'embrasse pas mais le coeur y est. ;-)
Commenter la réponse de sylvunix
cs_Loda 900 Messages postés vendredi 3 novembre 2000Date d'inscription 30 juillet 2009 Dernière intervention - 13 déc. 2006 à 09:21
0
Merci
salut,

je suis content que ça t'ai dépanné.

En passant, je me permet quelques petits commentaires sur ton code:

- il manque sérieussement un .destroy pour ton datamodule.

- LoadFromFile set Active à true. donc tu n'as pas besoin de le faire.

- je te conseille de changer ta signature de decode:

function decode (aFielName : string) : integer;
ou
function decode (aNode : IXMLNode) : integer;

en général, on évite d'intégrer les fonction d'affichage dans les class qui traite les données.
Aussi, tu dois pouvoir trouver un nom plus clair/précis pour ta méthode decode.

- suivant tes besoins, garde le xmldocument dans un champ de l'objet pour pouvoir le (re)lire plus tard sans avoir à le recharger. Si tu n'en a pas besoin, alors pourquoi as-tu mis le datamodule comme un champ? (dit autrement, soit tu fait des var local, soit des champs, mais évite de mélanger. t'as peut-être un petit défaut de design.)

aller, en espérant t'avoir aider.

A+

Loda

PS: on clique sur "réponse acceptée" sur le psot qui donne la réponse en général. pas ses propres posts. mais bon....
Commenter la réponse de cs_Loda
cs_Loda 900 Messages postés vendredi 3 novembre 2000Date d'inscription 30 juillet 2009 Dernière intervention - 13 déc. 2006 à 09:25
0
Merci
PS2:

si tu ne garde pas ton instance de class, (cad si tu las cree et la detruit dans la même procedure/methode) pourquoi ne fait tu pas une procedure? en effet, l'intérer des class c'est qu'elles conserve leur états. si t'as juste besoisnde lire une valeur et de fermer le fichier, fait plustot une procedure/function "toute seul".
-------------------
Loda
Commenter la réponse de cs_Loda
sylvunix 103 Messages postés mardi 11 avril 2006Date d'inscription 4 mars 2009 Dernière intervention - 13 déc. 2006 à 11:09
0
Merci
Je rectifie pour la réponse acceptée ... Je souhaitais uniquement mettre en valeur l'explication de la solution technique. Toutes mes excuses.

Quand au source joint dans mes messages, je te rassure, il n'était donné qu'à titre d'exemple pour illustrer mon problème. Je code en temps normal beaucoup mieux que cela (du moins j'en ai l'impression !).

A la lecture de ton message, je me suis quand même rendu compte que j'avais totalement oublié le destroy sur le datamodule (oups).

Je finalise mes sources que je pourrais ainsi bientôt déposer. J'espère que tu auras le temps d'y jeter un coup et de les critiquer.

Encore merci.
Commenter la réponse de sylvunix
cs_Loda 900 Messages postés vendredi 3 novembre 2000Date d'inscription 30 juillet 2009 Dernière intervention - 13 déc. 2006 à 16:21
0
Merci
salut,

Tu peux accepter les deux, comme ça les gens qui (peut-être) relirons ce post trouverons tout de suite les info utiles.

Sans problème, si j'ai un moment je jeterais un coup d'oeil. Si jamais envoye moi un MP avec le liens, je me connecte pas de manière régulière.

A+

Loda
<hr size="2" width="100%" />Se poser les bonnes questions est le premier pas pour avoir les bonnes réponses.
Commenter la réponse de cs_Loda
sylvunix 103 Messages postés mardi 11 avril 2006Date d'inscription 4 mars 2009 Dernière intervention - 19 janv. 2007 à 07:23
0
Merci
Vous pourrez trouver le source qui m'a posé problème sur delphifr.

Gestion de fichier de configuration

sylvunix
Commenter la réponse de sylvunix

Vous n'êtes pas encore membre ?

inscrivez-vous, c'est gratuit et ça prend moins d'une minute !

Les membres obtiennent plus de réponses que les utilisateurs anonymes.

Le fait d'être membre vous permet d'avoir un suivi détaillé de vos demandes et codes sources.

Le fait d'être membre vous permet d'avoir des options supplémentaires.