Mer 21/08/2013 - XML

Xavier
Administrateur du site
Messages : 817
Enregistré le : mer. 22 juin 2011 18:25

Mer 21/08/2013 - XML

Message non lu par Xavier »

XML


La prochaine tâche va être de réécrire la manière dont les fichiers XML sont lus.

Le code actuel n'est pas totalement mauvais, il cherche bien les éléments en les parsant récursivement (sans doute le seul moyen), le problème étant qu'une fois qu'il les a trouvé, il les traite via leur chemin complet.

Un peu comme si on voulait lister tous les fichiers d'un disque dur, la routine chercherait les fichiers dans chaque sous-dossier, mais la récupération des nom, taille et date de ses fichiers se ferait via "C:\Dossier\Sous-dossier\Sous-dossier\Sous-dossier\Sous-dossier\Sous-dossier\Fichier", ce qui en XML semble donc coûteux. Cette récupération se fera donc à partir du dernier élément trouvé et non à partir de la racine.


Un autre sujet de réflexion est apparu, qui concerne l'utilisation des éléments XML.

La première version d'une donnée XML était la copie conforme de la donnée XT4 :

Code : Tout sélectionner

//--------------------------------------------------------------------------------
// Modèle 1 (Original)
//	Chaque champ et chaque ligne d'une liste de textes est stocké dans un Tag
//--------------------------------------------------------------------------------
<Data>
	<Ident>123456789</Ident>
	<Model>Contact</Model>
	<Encrypted>False</Encrypted>
	<Properties>
		<Prop>Caption="Pro"</Prop>
		<Prop>Color="Red"</Prop>
	</Properties>
	<Text>
		<Line>Ceci est la ligne 1</Line>
		<Line>Ceci est la ligne 2</Line>
		<Line>Ceci est la ligne 3</Line>
		<Line>Ceci est la ligne 4</Line>
		<Line>Ceci est la ligne 5</Line>
	</Text>
	<Children>
		<Data>...</Data>
		<Data>...</Data>
		<Data>...</Data>
	</Children>
</Data>
C'est un peu long mais c'est clair comme de l'eau de roche.

Récemment, les lignes de <Text> ont été mergées, certaines de mes Notes faisant plusieurs milliers de lignes :

Code : Tout sélectionner

//--------------------------------------------------------------------------------
// Modèle 2 (Actuel)
//	Les lignes de la liste de textes <Text> sont concaténées en un seul élément
//	(¤ = caractère de fin de ligne)
//--------------------------------------------------------------------------------
<Data>
	<Ident>123456789</Ident>
	<Model>Contact</Model>
	<Encrypted>False</Encrypted>
	<Properties>
		<Prop>Caption="Pro"</Prop>
		<Prop>Color="Red"</Prop>
	</Properties>
	<Text>Ceci est la ligne 1¤Ceci est la ligne 2¤Ceci est la ligne 3¤Ceci est la ligne 4¤Ceci est la ligne 5</Text>
	<Children>
		<Data>...</Data>
		<Data>...</Data>
		<Data>...</Data>
	</Children>
</Data>
Le merge à l'écriture et le split à la lecture sont transparents, Delphi s'occupe nativement de ces tâches.
Cette solution pourrait donc être également utilisé pour <Properties>, la seconde liste de textes :

Code : Tout sélectionner

//--------------------------------------------------------------------------------
// Modèle 3
//	Les lignes de la liste de textes <Properties> sont concaténées aussi en un seul élément
//	(¤ = caractère de fin de ligne)
//--------------------------------------------------------------------------------
<Data>
	<Ident>123456789</Ident>
	<Model>Contact</Model>
	<Encrypted>False</Encrypted>
	<Properties>Caption="Pro"¤Color="Red"</Properties>
	<Text>Ceci est la ligne 1¤Ceci est la ligne 2¤Ceci est la ligne 3¤Ceci est la ligne 4¤Ceci est la ligne 5</Text>
	<Children>
		<Data>...</Data>
		<Data>...</Data>
		<Data>...</Data>
	</Children>
</Data>
Quitte à optimiser, tous les champs peuvent également être gérés en tant qu'attributs XML :

Code : Tout sélectionner

//--------------------------------------------------------------------------------
// Modèle 4
//	Les champs sont stockés en attribut, les listes d'éléments sont supprimées
//	(¤ = caractère de fin de ligne)
//--------------------------------------------------------------------------------
<Data Ident="123456789" Model="Contact" Encrypted="False">
	<Properties>Caption="Pro"¤Color="Red"</Properties>
	<Text>Ceci est la ligne 1¤Ceci est la ligne 2¤Ceci est la ligne 3¤Ceci est la ligne 4¤Ceci est la ligne 5</Text>
	<Children>
		<Data>...</Data>
		<Data>...</Data>
		<Data>...</Data>
	</Children>
</Data>
Tout cela n'aura aucun impact sur les données XT4, seule le stockage est ici en cause. On reste compatible XML à 100%.
Avoir moins d'éléments améliorera énormément les performances mais pourrait nuire à la lisibilité des fichiers.

Quant à la liste des Data enfants:

Code : Tout sélectionner

	<Children>
		<Data>...</Data>
		<Data>...</Data>
		<Data>...</Data>
	</Children>
une ultime optimisation de place pourrait être de supprimer le "container" :

Code : Tout sélectionner

	<Data>...</Data>
	<Data>...</Data>
	<Data>...</Data>
mais ajouter leur nombre comme attribut du "container" permettrait au contraire d'y accéder plus rapidement (en esquivant un Count) :

Code : Tout sélectionner

	<Children Count="3">
		<Data>...</Data>
		<Data>...</Data>
		<Data>...</Data>
	</Children>
Des avis ?
Xavier
Administrateur du site
Messages : 817
Enregistré le : mer. 22 juin 2011 18:25

Re: Mer 21/08/2013 - XML

Message non lu par Xavier »

Code : Tout sélectionner

	<Properties>Caption="Pro"¤Color="Red"</Properties>
pourrait même être passé en attributs lui aussi :

Code : Tout sélectionner

	<Properties Caption="Pro" Color="Red">
mais il faudra voir si cela ne demande pas de code complexe pour faire le split et le merge, car Delphi ne le fera pas.
Denis
Messages : 180
Enregistré le : jeu. 23 juin 2011 09:21

Re: Mer 21/08/2013 - XML

Message non lu par Denis »

Très bonne question, e dirais même question classique en XML: que mettre en attributs de noeud, et que mettre en sous-neuds?
Déjà, la question de la lisibilité des fichiers XT est un faux débat, la plupart du temps, les gens auront des fichiers cryptés, ou en tout cas leur attente ne sera pas de pouvoir les éditer via Notepad, Textpad...
Donc je dirais à toi de déterminer tes règles. Perso, j'aime bien:
- garder des containers genre 'ListOfTrucs' avec dessous des "Truc"
- le compteur ne sert à rien, c'est une propriété d'un noeud DOM, donc très rapide à avoir (count ou length, je sais plus)
- pour les propriétés, je serais d’avis de mettre un "identifiant unique" en attribut et le reste en contenu: <Data id="ma_prop18">Mavaleurdirecte ici</Data>, si besoin rajouter d'autres infos en attribut comme le type de la donnée, sa longueur, si elle est cryptée... <Data id="ma_prop18" encrypted="true" length="12" type="string">UYVIVZCUZFEZ</Data>.
- Pour les properties, je garderais une ligne par Property... mais bon, à voir en effet
- souvent en XML, tu mets les attibuts, les noms de noeuds en minuscule. Mais SGML te permet de faire ce que tu veux: attention aux valeurs des attributs de noeud: tu as des contraintes à respecter (genre caractères spéciaux & < > interdits ou à déclarer comme "entités Xml"...) ou sinon les placer en contenu de noeud dans un CDATA.
Xavier
Administrateur du site
Messages : 817
Enregistré le : mer. 22 juin 2011 18:25

Re: Mer 21/08/2013 - XML

Message non lu par Xavier »

Merci pour ton avis :), également discuté avec le FBu plus tôt...
Déjà, la question de la lisibilité des fichiers XT est un faux débat, la plupart du temps, les gens auront des fichiers cryptés, ou en tout cas leur attente ne sera pas de pouvoir les éditer via Notepad, Textpad...
C'est vrai, il faut viser la perf en premier. De toute façon, si la "concaténation" des tags peut réduire la lisibilité, la réduction du nombre de ligne aide à retrouver ses petits, donc ça doit se valoir...
- garder des containers genre 'ListOfTrucs' avec dessous des "Truc"
- le compteur ne sert à rien, c'est une propriété d'un noeud DOM, donc très rapide à avoir (count ou length, je sais plus)
Oui tu as raison, je vais rester sur le modèle existant pour les <Children>.
- pour les propriétés, je serais d’avis de mettre un "identifiant unique" en attribut et le reste en contenu: <Data id="ma_prop18">Mavaleurdirecte ici</Data>, si besoin rajouter d'autres infos en attribut comme le type de la donnée, sa longueur, si elle est cryptée... <Data id="ma_prop18" encrypted="true" length="12" type="string">UYVIVZCUZFEZ</Data>.
L'idéal en effet serait de regrouper certains champs dans des attributs d'un même élément mais cela veut dire coder ces groupes, (surtout pour les options !) mais je veux rester générique.
- Pour les properties, je garderais une ligne par Property... mais bon, à voir en effet
Oui ça va sans doute rester comme ça : il y en a peu dans les Data . Un peu plus dans les Options mais le fichier est petit donc pas de problème de perf. Et puis comme ça c'est beau. 8-)


Bon pour le moment je vais rester sur le modèle existant (n° 2). Si après avoir corrigé l'algo de lecture c'est toujours trop lent, je passerai le fichier des données en mode "compressé" (n° 4), avec option pour l'avoir en mode "complet" si besoin. Le fichier des options restera en mode n°2. Le merge des <Lines> de <Text> a déjà fait beaucoup de bien et j'arrive à me le justifier donc tout va bien...
Xavier
Administrateur du site
Messages : 817
Enregistré le : mer. 22 juin 2011 18:25

Re: Mer 21/08/2013 - XML

Message non lu par Xavier »

Il y a une fonction de dédoublonnage dans le chargement des enfants d'une donnée XT4. :shock:
Impossible de savoir pourquoi elle a été ajoutée, ce code ayant été écrit il y a deux ans, mais il est certain que cette fonction devait bien ralentir le chargement.
Elle a été supprimée, en espérant qu'elle ne sera pas à remettre... lol
Xavier
Administrateur du site
Messages : 817
Enregistré le : mer. 22 juin 2011 18:25

Re: Mer 21/08/2013 - XML

Message non lu par Xavier »

XMo a écrit :Il y a une fonction de dédoublonnage dans le chargement des enfants d'une donnée XT4.
Impossible de savoir pourquoi elle a été ajoutée, ce code ayant été écrit il y a deux ans, mais il est certain que cette fonction devait bien ralentir le chargement.
Elle a été supprimée, en espérant qu'elle ne sera pas à remettre...
Cette fonction était en fait indispensable : un arbre d'options par défaut est créé au tout début du démarrage et il est mis à jour avec les options du fichier, s'il existe. Sans le dédoublonnage, l'arbre des options est dupliqué au second démarrage. La fonction a donc été remise, mais uniquement pour le fichier des options. (L'arbre contient aussi des constantes internes non sauvées dans le fichier donc pas moyen de ne l'initialiser que si le fichier des options n'existe pas.)

Le résultat de la réécriture des méthodes LoadFromFile et LoadFromNode est simplement spectaculaire ! :o
Cela prend visuellement autant de temps pour démarrer XT4 à vide ou avec un fichier de 1.4 Mo (1050 entrée de Calendrier et 110 Notes).

Le SelectSingleNode est toujours utilisé par deux petits services qui servent à récupérer les Nodes des deux listes et les valeurs des 4 champs "nominatifs". Mais cette fois l'instruction est utilisée en mode "local" (./XPath) comme conseillé partout. Le reste est récursif et utilise du HasChildNodes, ChildNodes.Length et ChildNodes[Index]. Tout le code a été épuré.

Code : Tout sélectionner

	//----------------------------------------------------------------------
	function GetNode(Node: IXMLDOMNode; Node_Name: String): IXMLDOMNode;
	begin
		Result := Node.SelectSingleNode('./' + Node_Name);
	end;
	//----------------------------------------------------------------------
	function GetNodeText(Node: IXMLDOMNode; Node_Name: String): String;
	var
		Child_Node: IXMLDOMNode;
	begin
		Child_Node := GetNode(Node, Node_Name);
		if	Assigned(Child_Node)
		then	Result := Child_Node.Text
		else	Result := '';
	end;
	//----------------------------------------------------------------------
La sauvegarde prend aussi 2 secondes mais ce sera pour plus tard, car le prochain chantier est le dernier outil : Copier-coller.
Denis
Messages : 180
Enregistré le : jeu. 23 juin 2011 09:21

Re: Mer 21/08/2013 - XML

Message non lu par Denis »

gratz !
Répondre