Tuto sur NSXML

VeillardVeillard Membre
23:52 modifié dans API AppKit #1
Bonjour à  tous  ;)

Je cherche un tuto éventuellement des exemples permettant d'exporter des données en XML via NSXML sour 10.4. En fait, je cherche à  exporter des données au format UDCF (Universal Dive Computer Format) qui est dans un format XML. Puis dans un deuxième temps, je me pencherai sur l'importation de des données en UDCF.

Merci d'avance. A+
«1

Réponses

  • AliGatorAliGator Membre, Modérateur
    23:52 modifié #2
    Salut

    Pour avoir travaillé sur un soft qui fait du XML, et pour être en train de "faire un tuto en live" à  un pote (tuto que je publierai quand je l'aurais fini et mis en page), j'ai bien peur de devoir t'annoncer qu'il n'existe rien pour exporter en XML

    NSXMLParser est une classe simple pour gérer du XML de façon evènementielle (ça appelle des méthodes de delegate à  chaque fois que ça rencontre un tag ouvrant (avec ses attributs en paramètre), un tag fermant, du texte brut...
    C'est assez simple à  utiliser en fait (y'a juste à  implémenter les méthodes de delegate dont tu as besoin) pour parser un XML de base comme on en voit partout.

    Les autres classes NSXML* sont pour une approche plus précise des XML (y compris les "processing instructions" que l'on peut trouver dans les XSLT ou des trucs "haut niveau" comme ça, je veux dire qu'on ne voit que très rarement dans les XMLs "de tous les jours"), mais toujours pour parser un XML, c'est à  dire le lire et l'interpréter.

    Perso, quoique j'aimerai bien qu'on me dise que ça existe, en tout cas j'ai rien trouvé pour ecrire (== produire, exporter, créer... t'appelles ça comme tu veux) du XML. Donc dans ce cas on est obligé de se le taper à  la main.
    Dans mon tuto que je suis en train de préparer* j'ai écrit une classe "ALIXMLExporter" qui prend un NSDictionary (en fait c'est même le arrangedObjects d'un NSArrayController pour tout te dire) et l'enregistre en XML dans le fichier de notre choix


    *mauvaise nouvelle, je suis en train de refaire mon site web pour la 3e fois (je suis du genre à  essayer tout plein de trucs sympas en CSS mais en fait je l'ai toujours pas rempli :p) donc le tuto ne sera pas forcément en ligne rapidement

    N'hésites-pas à  me contacter si tu veux que je mette quelques infos à  ta disposition en avant-première avant de tout mettre au propre pour le publier pour tout le monde. Mais pour ce que j'en sais, le plus simple est de faire une classe dédiée à  cet export car je n'ai rien trouvé dans les classes Apple pour le faire.
  • AliGatorAliGator Membre, Modérateur
    23:52 modifié #3
    Une petite info supplémentaire :
    Le plus simple est de spécifier dans ton header XML que ton texte est en encodage UTF8, ce qui est vrai en général pour tes NSStrings, et ensuite :
    - soit de mettre tous tes morceaux de texte brut dans un bloc "[tt]<[CDATA/tt]&quot; ... &quot;[tt]>[/tt]" pour être sûr qu'il n'y ait pas de caractères spéciaux qui auraient dû être échappés
    - soit d'échapper les caractères spéciaux, ce qui en soit n'est pas compliqué car dans la norme XML il n'y en a que 5 à  échapper, pas plus : <, >, &, " et ' (respectivement en [tt]&lt;[/tt], [tt]&gt;[/tt], [tt]&amp;[/tt], [tt]&quot;[/tt] et [tt]&apos;[/tt]). Les autres tu peux les laisser tels quels.
    - Et faire gaffe que tes clés de ton dictionnaire, qui seront tes tags XML, sont des tags valides (le classique : en un seul mot, ne contenant que des caractères alphanumériques ou des underscores, mais ne commençant pas par un chiffre)

    Enfin y'a 2-3 petites conneries à  faire gaffe pour ce genre de cas particuliers. Sinon c'est pas compliqué à  faire il suffit de parcourir ton NSDico ou NSArray de NSDico et demander à  chaque élément de générer sa partie de XML sous forme de NSString.
  • BruBru Membre
    23:52 modifié #4
    dans 1147116546:

    j'ai bien peur de devoir t'annoncer qu'il n'existe rien pour exporter en XML


    Cocoa autorise la création d'un document XML à  partir de rien, puis ensuite de l'exporter sous forme de fichier.
    La gestion de ce document XML sous cocoa ressemble beaucoup (enfin de mon point de vue) à  la gestion du DOM par javascript.

    .
  • BruBru Membre
    23:52 modifié #5
    dans 1147005023:

    Je cherche un tuto éventuellement des exemples permettant d'exporter des données en XML via NSXML sour 10.4. En fait, je cherche à  exporter des données au format UDCF (Universal Dive Computer Format) qui est dans un format XML. Puis dans un deuxième temps, je me pencherai sur l'importation de des données en UDCF.


    Ce n'est pas un tuto, mais voici le code qui génère le début d'un fichier xml UDCF :

    <br />{<br />&nbsp; &nbsp; NSXMLDocument *udcf;<br />&nbsp; &nbsp; NSXMLElement *root, *element;<br /><br />&nbsp; &nbsp; // création d&#39;un document XML<br />&nbsp; &nbsp; udcf=[[NSXMLDocument alloc] init];<br /><br />&nbsp; &nbsp; // création du rootNode (élément le + haut dans la hiérarchie XML)<br />&nbsp; &nbsp; // ici, c&#39;est l&#39;élément PROFILE pour un fichier UDCF.<br />&nbsp; &nbsp; root=[NSXMLElement elementWithName:@&quot;PROFILE&quot;];<br /><br />&nbsp; &nbsp; // ajout de l&#39;attribut UDCF de valeur 1 à  l&#39;élément PROFILE<br />&nbsp; &nbsp; [root addAttribute:[NSXMLNode attributeWithName:@&quot;UDCF&quot; stringValue:@&quot;1&quot;]];<br /><br />&nbsp; &nbsp; // l&#39;élément PROFILE devient donc le rootNode du document XML<br />&nbsp; &nbsp; [udcf setRootElement:root];<br /><br />&nbsp; &nbsp; // ajout d&#39;un peu de blabla<br />&nbsp; &nbsp; [root addChild:[NSXMLElement commentWithStringValue:@&quot;This file was generated by Bru&quot;]];<br />&nbsp; &nbsp; [root addChild:[NSXMLElement commentWithStringValue:@&quot;Converted for: Favouille&quot;]];<br />&nbsp; &nbsp; [root addChild:[NSXMLElement commentWithStringValue:@&quot;Date: 8 mai 06&quot;]];<br /><br />&nbsp; &nbsp; // création du node UNITS de valuer &quot;Metrics&quot; et ajout dans le rootNode<br />&nbsp; &nbsp; element=[NSXMLElement elementWithName:@&quot;UNITS&quot; stringValue:@&quot;Metric&quot;];<br />&nbsp; &nbsp; [root addChild:element];<br /><br />&nbsp; &nbsp; // création du node DEVICE<br />&nbsp; &nbsp; element=[NSXMLElement elementWithName:@&quot;DEVICE&quot;];<br /><br />&nbsp; &nbsp; // ajout dans le node DEVICE les nodes VENDOR, MODEL et VESRION avec leur valeur respective<br />&nbsp; &nbsp; [element addChild:[NSXMLElement elementWithName:@&quot;VENDOR&quot; stringValue:@&quot;Suunto&quot;]];<br />&nbsp; &nbsp; [element addChild:[NSXMLElement elementWithName:@&quot;MODEL&quot; stringValue:@&quot;Eon&quot;]];<br />&nbsp; &nbsp; [element addChild:[NSXMLElement elementWithName:@&quot;VERSION&quot; stringValue:@&quot;1&quot;]];<br /><br />&nbsp; &nbsp; // ajout du node DEVICE dans le rootNode<br />&nbsp; &nbsp; [root addChild:element];<br /><br />&nbsp; &nbsp; // écriture du document XML vers un fichier<br />&nbsp; &nbsp; [[udcf XMLData] writeToFile:@&quot;/udcf.xml&quot; atomically:NO];<br /><br />&nbsp; &nbsp; // nettoyage<br />&nbsp; &nbsp; [udcf release];<br />}<br />
    


    Le fichier créé se conforme à  ce fichier UDCF qu'on trouve un peu partout sur le net :
    [tt]<PROFILE UDCF="1">
    <!-- This file was generated by 'eonconvert' -->
    <!-- Converted for: streit@kurgan.mayn.de -->
    <!-- Date: Thu Dec 30 19:07:57 MET 1999 -->
    <UNITS>Metric</UNITS>
    <DEVICE>
    <VENDOR>Suunto</VENDOR>
    <MODEL>EON</MODEL>
    <VERSION>1</VERSION>
    </DEVICE>
    [/tt]

    .
  • AliGatorAliGator Membre, Modérateur
    mai 2006 modifié #6
    Renaud, tu m'as encore raconté des conneries... >:)

    :D

    merci Bru, vais voir si je peux creuser de ce côté là  (p'tet pas pour mon tuto en cours avec mon "élève", mais pour plus tard) moi aussi car du coup ça m'intéresse :)
  • 23:52 modifié #7
    dans 1147127112:

    Renaud, tu m'as encore raconté des conneries... >:)


    Voilà  ce qui arrive quand on dépasse le quota :fouf):
  • VeillardVeillard Membre
    23:52 modifié #8
    Merci à  tous pour vos réponses. Je vais finalement adopter la solution de Bru qui me convient particulièrement. J'avais fait de l'XML en exportant un fichier texte aves des MutableString, solution que je jugeais un peu lourde...

    A+
  • VeillardVeillard Membre
    23:52 modifié #9
    @Bru

    Ta méthode fonctionne très bien, par contre j'ai tous mes tags à  la queue leu leu, point de sauts de ligne ???
  • BruBru Membre
    mai 2006 modifié #10
    dans 1147197939:

    @Bru

    Ta méthode fonctionne très bien, par contre j'ai tous mes tags à  la queue leu leu, point de sauts de ligne ???


    Ca n'a aucune importance.
    Le format XML n'impose pas de retour à  la ligne (c'est juste une convention d'affichage pour faciliter la lecture du fichier en mode texte). D'ailleurs, les sauts de ligne, les tabulations et autres espaces surnuméraires sont tout simplement ignorés lors du parsing d'un document XML.

    D'ailleurs, si tu ouvres le fichier dans un parseur XML, les sauts se feront automatiquement (essaie d'ouvrir ton fichier dans FireFox, et tu verras).

    Sinon tu veux vraiment avoir des sauts de ligne, remplace
    [[udcf XMLData] writeToFile:@&quot;/udcf.xml&quot; atomically:NO];
    


    par
    [[udcf XMLStringWithOptions:NSXMLNodePrettyPrint] writeToFile:@&quot;/udcf.xml&quot; atomically:NO];
    


    .
  • VeillardVeillard Membre
    23:52 modifié #11
    OK merci pour tes lumières  ;)
  • VeillardVeillard Membre
    23:52 modifié #12
    Tout fonctionne nickel, j'ai commencé à  jeter un oeil sur l'import des données UDCF et apparemment, c'est une autre paires de manches...
  • VeillardVeillard Membre
    mai 2006 modifié #13
    Bon, j'ai jeté un oeil... du coup, j'ai quelques questions :  :o

    - pour lire mon fichier XML (UDCF) faut-il initialiser un NSXMLDocument (avec initWithData:options:error:) avant de récupérer les valeurs contenues entre les tags ?
    - sinon j'ai vu quelque chose comme (objectByApplyingXSLT:arguments:error:), que veut dire XSLT ? Apparemment ça permet de transformer un doc XML en un autre doc XML, je ne pense pas que ce soit adapté à  mon cas ???

    Je viens de voir quelque chose du style "Traversing an XML Tree" ça m'a l'air plus sérieux...
  • AliGatorAliGator Membre, Modérateur
    mai 2006 modifié #14
    Salut,

    1) Oui bien sûr : il faut créer une instance de NSXMLDocument en lui passant dans le init les data à  parser. Ce que tu peux faire avec initWithData:options:error: si tu as les données directement sous forme de NSData, mais souvent on le fait plutôt avec [tt]initWithContentsOfURL:options:error:[/tt] si tu as plutôt un chemin vers le fichier XML à  lire (à  transformer en NSURL), ou [tt]initWithXMLString:options:error:[/tt] si tu as le contenu du XML déjà  dans une NSString.
    Et une fois que ton instance de NSXMLDocument est créée et initialisée avec un contenu XML, là  tu peux parcourir et récupérer le contenu.

    2) Les XSLT ce sont des documents permettant de faire des transformations XML (et ces documents sont eux-mêmes écrits en XML). C'est pratique pour convertir un XML en un autre XML en faisant des manipulations sur les nodes (avec les "processing instructions" du langage XML par exemple), ou pour transformer un XML en page HTML pour l'afficher dans un navigateur sous forme de page web... bref tout ça tu n'en as pas besoin. Ni tout ce qui concerne XSLT, ni ce qui concerne les processing instructions.

    Il faut savoir que le langage XML est très très riche et que les documents XML que l'on "voit tous les jours" dans 98% des cas n'utilisent que la partie la plus simple et la plus courante de XML, c'est à  dire les "bêtes" tags avec des attributs et des tags enfants. Parfois un DTD pour spécifier le format du XML (conditions à  respecter entre les noeuds, etc), mais l'utilisation des namespaces, processing instructions et tout en général tu peux ignorer car tu n'utiliseras pas.

    Sinon sache que pour parser un document XML tu as 2 possibilités : soit avec NSXMLDocument (c'est du parsing DOM il me semble dans ce cas ? C'est à  dire pas évènementiel, mais ça te parse tout le XML tree direct et tu le parcourres ensuite), soit avec NSXMLParser (ça c'est du SAX, c'est à  dire de l'évènementiel, c'est à  dire qu'il envoie à  ton delegate un message à  chaque fois qu'il ouvre un tag (+ attributs du tag), ferme un tag, ou rencontre du texte brut (y'a d'autres méthodes de delegate mais c'est les plus utiles).

    Perso moi j'aime bien NSXMLParser je trouve ça aussi très simple à  utiliser pour parser un document (t'as juste en gros 3 méthodes de delegate à  implémenter, et dans chacune tu mets des if ou des switch partout, mais c'est tout).

    Maintenant c'est vrai que si tu utilises NSXMLDocument pour écrire ton doc, c'est peut-être aussi propre (juste pour faire "symétrique" mais en fait aucune obligation technique) d'utiliser aussi NSXMLDocument pour parser/lire ton doc aussi.



    3) Sinon je n'ai que peu utiliser NSXMLDocument du coup, mais je pense que pour naviguer dans le doc XML une fois parsé, il faut utiliser la méthode [tt]rootElement[/tt] pour récupérer l'élément XML racine de ton XML, et à  partir de ce rootElement (NSXMLElement), et ensuite du accèdes aux éléments enfants de ce node, puis aux enfants des enfants, etc (avec [tt]elementsForName:[/tt] par exemple, j'imagine)
  • VeillardVeillard Membre
    23:52 modifié #15
    Merci pour toutes ces infos Ali, je vais étudier ça demain à  tête reposée. 
  • BruBru Membre
    mai 2006 modifié #16
    Des 2 solutions de parsing proposées par Aligator, il y a la moderne/élégante (NSXMLParser) et la pratique (parsing manuel de NSXMLDocument).

    Dans le cas d'un fichier UDCF, j'utiliserai plutôt la seconde méthode.

    Je te donne un exemple qui va récupérer la première plongée du profil pour retourner la date (sous forme de NSDate) et un NSArray des profondeurs :
    <br />#import &quot;controleur.h&quot;<br />#import &quot;BRUView.h&quot;<br /><br />NSCalendarDate* GetCalendarDateFromElement(NSXMLElement *element);<br /><br />@implementation controleur<br /><br />- (void)readUDCF<br />{<br />   NSXMLDocument *udcf;<br />   NSError *erreur;<br />   NSXMLElement *rootElement, *tmpElement;<br />   NSArray *tmpArray;<br />   NSDate *datePlongee;<br />   NSMutableArray *profil;<br />   NSEnumerator *enumerator;<br />   id object;<br /><br />   udcf=[[NSXMLDocument alloc] initWithContentsOfURL:[NSURL fileURLWithPath:@&quot;/test-udcf.xml&quot;] options:NSXMLDocumentTidyXML error:&amp;erreur];<br /><br />   // y&#39;a une erreur : on ne fait rien<br />   if (erreur!=nil) return;<br />   {<br />      NSLog(@&quot;erreur : %@&quot;, erreur);<br />      [udcf release];<br />      return;<br />   }<br /><br />   // récup du rootNode (normalement un PROFILE)<br />   rootElement=[udcf rootElement];<br /><br />   // récup du node REPGROUP<br />   tmpElement=[[rootElement elementsForName:@&quot;REPGROUP&quot;] lastObject];<br /><br />   // récup du premier node de REPGROUP : le DIVE !<br />   tmpElement=[[tmpElement elementsForName:@&quot;DIVE&quot;] objectAtIndex:0];<br /><br />   // dans DIVE, récup de la date<br />   datePlongee=GetCalendarDateFromElement([[tmpElement elementsForName:@&quot;DATE&quot;] lastObject]);<br />   NSLog(@&quot;date de plongée %@&quot;, datePlongee);<br /><br />   // accès au SAMPLES dans DIVE (profil de plongée)<br />   tmpElement=[[tmpElement elementsForName:@&quot;SAMPLES&quot;] objectAtIndex:0];<br /><br />   // dans SAMPLES, récup du tableau des nodes D (profondeur)<br />   tmpArray=[tmpElement elementsForName:@&quot;D&quot;];<br /><br />   // transformation du tableau de node D en NSArray de NSNumber<br />   profil=[[NSMutableArray alloc] initWithCapacity:[tmpArray count]];<br />   enumerator=[tmpArray objectEnumerator];<br />   while (object=[enumerator nextObject])<br />   {<br />      [profil addObject:[NSNumber numberWithFloat:[[object stringValue] floatValue]]];<br />   }<br />   NSLog(@&quot;profil %@&quot;, profil);<br />   [profil release];<br /><br />   [udcf release];<br />}<br /><br />@end<br /><br />NSCalendarDate* GetCalendarDateFromElement(NSXMLElement *element)<br />{<br />   int jour, mois, annee;<br />   int heure, minute;<br />   NSXMLElement *tmpElement, *timeElement;<br /><br />   // récupération du jour<br />   tmpElement=[[element elementsForName:@&quot;DAY&quot;] lastObject];<br />   jour=[[tmpElement stringValue] intValue];<br /><br />   // récupération du mois<br />   tmpElement=[[element elementsForName:@&quot;MONTH&quot;] lastObject];<br />   mois=[[tmpElement stringValue] intValue];<br /><br />   // récupération de l&#39;année<br />   tmpElement=[[element elementsForName:@&quot;YEAR&quot;] lastObject];<br />   annee=[[tmpElement stringValue] intValue];<br /><br />   // maintenant, on tente de récupérer un node frère de type TIME<br />   timeElement=[[((NSXMLElement *)[element parent]) elementsForName:@&quot;TIME&quot;] lastObject];<br /><br />   // TIME trouvé : récup de l&#39;heure<br />   if (timeElement!=nil)<br />   {<br />      // récupération de l&#39;heure<br />      tmpElement=[[timeElement elementsForName:@&quot;HOUR&quot;] lastObject];<br />      heure=[[tmpElement stringValue] intValue];<br /><br />      // récupération des minutes<br />      tmpElement=[[timeElement elementsForName:@&quot;MINUTE&quot;] lastObject];<br />      minute=[[tmpElement stringValue] intValue];<br />   }<br />   else<br />   {<br />      heure=0;<br />      minute=0;<br />   }<br /><br />   return [NSCalendarDate dateWithYear:annee month:mois day:jour hour:heure minute:minute second:0 timeZone:nil];<br />}
    


    Il y a plusieurs moyens de parcourir l'arbre XML : j'ai choisi le plus simple, mais pas le plus optimisé.
    A toi de partir de cet exemple pour le développer.

    .
  • VeillardVeillard Membre
    23:52 modifié #17
    Merci beaucoup Bru pour ton aide ! Je vais étudier ça de très près  :o
  • VeillardVeillard Membre
    mai 2006 modifié #18
    ça fume, ça fume... je m'arrache les cheveux. En fait, l'importation se fait bien pour une plongée. Lorsque je veux importer plusieurs plongées à  la fois je galère.

    - (IBAction)readUDCF:(id)sender<br />{<br />&nbsp;  NSXMLDocument	*udcf;<br />&nbsp;  NSError			*erreur;<br />&nbsp;  NSXMLElement		*rootElement, *tmpElement;<br />&nbsp;  NSArray			*tmpArray;<br />&nbsp;  NSDate			*datePlongee;<br />&nbsp;  NSMutableArray	*profil;<br />&nbsp;  NSEnumerator		*enumerator;<br />&nbsp;  id object;<br /><br />&nbsp;  udcf=[[NSXMLDocument alloc] initWithContentsOfURL:[NSURL fileURLWithPath:@&quot;/Volumes/Documents/Users/favouille/Desktop/test-udcf.xml&quot;] options:NSXMLDocumentTidyXML error:&amp;erreur];<br /><br />&nbsp;  // y&#39;a une erreur : on ne fait rien<br />&nbsp;  if (erreur != nil)<br />&nbsp;  {<br />&nbsp; &nbsp; &nbsp; NSLog(@&quot;erreur : %@&quot;, erreur);<br />&nbsp; &nbsp; &nbsp; [udcf release];<br />&nbsp; &nbsp; &nbsp; return;<br />&nbsp;  }<br /><br />	// récup du rootNode (normalement un PROFILE)<br />	rootElement = [udcf rootElement];<br /><br />	// récup du node REPGROUP<br />	tmpElement = [[rootElement elementsForName:@&quot;repgroup&quot;] lastObject];<br /><br />&nbsp;  <br />	int cpt, total;<br />	total = [[tmpElement elementsForName:@&quot;dive&quot;] count];<br />&nbsp;  <br /><br />//	for (cpt = 0 ; cpt &lt; total ; cpt++)<br />//	{<br />		// récup du premier node de REPGROUP : le DIVE !<br />		tmpElement = [[tmpElement elementsForName:@&quot;dive&quot;] objectAtIndex:0];<br />		<br />		// dans DIVE, récup de la date<br />		[dateField setDateValue:GetCalendarDateFromElement([[tmpElement elementsForName:@&quot;date&quot;] lastObject])];<br /><br />		[lieuField setStringValue:[[[tmpElement elementsForName:@&quot;place&quot;] lastObject] stringValue]];<br /><br />		[tempEauField setStringValue:[[[tmpElement elementsForName:@&quot;temperature&quot;] lastObject] stringValue]];<br /><br />		// accès au SAMPLES dans DIVE (profil de plongée)<br />		tmpElement = [[tmpElement elementsForName:@&quot;samples&quot;] objectAtIndex:0];<br /><br />		// dans SAMPLES, récup du tableau des nodes D (profondeur)<br />		tmpArray = [tmpElement elementsForName:@&quot;d&quot;];<br /><br />		// transformation du tableau de node D en NSArray de NSNumber<br />		profil = [[NSMutableArray alloc] initWithCapacity:[tmpArray count]];<br />		enumerator = [tmpArray objectEnumerator];<br />		<br />		while (object = [enumerator nextObject])<br />		{<br />			[profil addObject:[NSNumber numberWithFloat:[[object stringValue] floatValue]]];<br />		}<br />		[profil release];<br /><br />		[_carnet addObject:[self addPlongee]];<br />//	}<br />&nbsp;  [udcf release];<br />&nbsp;  <br />&nbsp;  [_plongeesTableView reloadData];<br />}
    


    Je voulais faire une boucle "for" avec "cpt" le nombre de plongées dans mon fichier XML. Ce que je n'arrive pas à  faire c'est savoir où mettre ce compteur pour passer à  la plongée suivante lors de la lecture des tags <dive></dive>, j'ai à  chaque fois "-[NSCFArray objectAtIndex:]: index (0) beyond bounds (0)". La question est : où je dois mettre ce foutu compteur... ???
  • VeillardVeillard Membre
    23:52 modifié #19
    J'ai enfin compris comment ça fonctionne  :brule: Pour revenir en arrière d'un tag, il faut redéfinir entièrement le chemin à  moins qu'il y ait une autre solution...

    // récup du node REPGROUP<br />	tmpElement = [[rootElement elementsForName:@&quot;repgroup&quot;] lastObject];<br /><br />&nbsp;  <br />	int cpt, total;<br />	total = [[tmpElement elementsForName:@&quot;dive&quot;] count];<br />&nbsp;  <br /><br />	for (cpt = 0 ; cpt &lt; total ; cpt++)<br />	{<br />		// récup du node REPGROUP<br />		tmpElement = [[rootElement elementsForName:@&quot;repgroup&quot;] lastObject];<br />		// récup du premier node de REPGROUP : le DIVE !<br />		tmpElement = [[tmpElement elementsForName:@&quot;dive&quot;] objectAtIndex:cpt];<br />		<br />		[lieuField setStringValue:[[[tmpElement elementsForName:@&quot;place&quot;] lastObject] stringValue]];<br />		[dateField setDateValue:GetCalendarDateFromElement([[tmpElement elementsForName:@&quot;date&quot;] lastObject])];<br />		[heureField setDateValue:GetCalendarDateFromElement([[tmpElement elementsForName:@&quot;time&quot;] lastObject])];<br />
    


    Voici le correctif...
  • AliGatorAliGator Membre, Modérateur
    mai 2006 modifié #20
    Ben heu c'est normal en fait : puisque tu modifies ta variable tmpElement avec la ligne [tt]tmpElement = [[tmpElement elementsForName:@dive] objectAtIndex:0];[/tt] !

    Donc le coup d'après tu demandes l'élément qui a le nom "dive"... à  l'intérieur de l'élément tmpElement... qui est déjà  un élément "dive" puisqu'il a été défini ainsi au passage d'avant de la boucle !

    Si tu ne veux pas "redéfinir tout le chemin", crée un autre élément :
    NSXMLElement *repgroupElement;<br />NSArray *diveElementsArray;<br /><br />// ...<br /><br />// récup du rootNode (normalement un PROFILE)<br />rootElement = [udcf rootElement];<br />// récup du node REPGROUP<br />repgroupElement = [[rootElement elementsForName:@&quot;repgroup&quot;] lastObject];<br />diveElemsArray = [repgroupElement elementsForName:@&quot;dive&quot;]; // tableau contenant tous les éléments &lt;dive&gt; du repgroup<br /><br />// Et là  tu peux boucler sur tes éléments dive qui sont dans le tableau<br />// comme tu parcourrerais n&#39;importe quel tableau !!<br /><br />int cpt, total;<br />total = [diveElemsArray count];<br /><br />for (cpt = 0 ; cpt &lt; total ; cpt++)<br />{<br />	tmpElement = [diveElemsArray objectAtIndex:cpt];<br />	// ... etc<br />}
    
    Tu peux remplacer ta boucle for par un NSEnumerator et une boucle while, c'est comme tu préfères, dans tous les cas avec le NSArray "diveElemsArray" tu peux naviguer dans ton tableau d'éléments "<dive>" comme tu le ferais dans n'importe quel NSArray !
    NSXMLElement* diveElem<br />NSEnumerator* e = [diveElemsArray objectEnumerator];<br />while( (diveElem = [e nextObject]) )<br />{<br />	// et là  tu fais mumuse avec le NSXMLElement &quot;diveElem&quot;<br />	// ...<br />}
    
  • VeillardVeillard Membre
    23:52 modifié #21
    Merci Ali, je vais pouvoir simplifier tout ça...

    Sinon comment peut-on avoir la fenêtre de navigation pour l'ouverture d'un fichier pour éviter d'écrire le path en entier comme ci-dessous. J'ai essayé [self fileName] mais ce n'est pas recommandé paraà®t-il...

    &nbsp; udcf=[[NSXMLDocument alloc] initWithContentsOfURL:[NSURL fileURLWithPath:@&quot;/Volumes/Documents/Users/favouille/Desktop/test-udcf.xml&quot;]
    
  • BruBru Membre
    23:52 modifié #22
    dans 1147539129:

    Sinon comment peut-on avoir la fenêtre de navigation pour l'ouverture d'un fichier pour éviter d'écrire le path en entier comme ci-dessous. J'ai essayé [self fileName] mais ce n'est pas recommandé paraà®t-il...


    Tu veux dire ça :
    <br />- (IBAction)importer:(id)sender<br />{<br />   NSOpenPanel *openPanel;<br /><br />   // récup de la fenêtre d&#39;ouverture de fichier<br />   openPanel=[NSOpenPanel openPanel];<br /><br />   // initialisation<br />   [openPanel setCanChooseFiles:YES];<br />   [openPanel setCanChooseDirectories:NO];<br />   [openPanel setAllowsMultipleSelection:NO];<br /><br />   // affichage de la fenêtre d&#39;ouverture en tant que sheet à  la fenêtre wnd<br />   [openPanel beginSheetForDirectory:nil<br />            file:nil<br />            types:[NSArray arrayWithObjects:@&quot;txt&quot;, @&quot;xml&quot;, @&quot;udcf&quot;, nil]<br />            modalForWindow:wnd<br />            modalDelegate:self<br />            didEndSelector:@selector(openPanelDidEnd:returnCode:contextInfo:)<br />            contextInfo:NULL];<br />}<br /><br />// quand la fenêtre est fermée, cette méthode est appelée<br />- (void)openPanelDidEnd:(NSOpenPanel *)panel returnCode:(int)returnCode contextInfo:(void *)contextInfo<br />{<br />   NSURL *urlUdcf;<br /><br />   if (returnCode==NSOKButton)<br />   {<br />      urlUdcf=[[panel URLs] lastObject];<br />      NSLog(@&quot;le fichier à  lire : %@&quot;, urlUdcf);<br />      // et je commence la lecture du fichier...<br />   }<br />}<br />
    


    .
  • VeillardVeillard Membre
    23:52 modifié #23
    C'est ce que j'ai vu en effet, je pensais qu'il y avait quelque chose de plus simple mais ça me convient très bien. Merci  ;)
  • AliGatorAliGator Membre, Modérateur
    23:52 modifié #24
    Salut

    Tu as une autre solution que celle proposée par Bru, mais qui est moins personnalisable d'une part, et qui affiche une fenêtre modale et non pas une sheet window d'autre part.

    En général je préfère la méthode de Bru car elle fait un truc plus standard (les sheets) et plus customisable, mais c'est bon de connaà®tre l'autre aussi (qui en plus évite de découper ton code en 2 méthodes à  cause du didEndSelector)
    NSOpenPanel* op = [NSOpenPanel openPanel];<br />	int ret = [op runModalForDirectory:nil file:nil types:[NSArray arrayWithObjects:@&quot;xml&quot;,nil]];<br />	if (ret == NSCancelButton)<br />		return;<br />	<br />	NSString* path = [[op filenames] objectAtIndex:0];<br />
    
  • VeillardVeillard Membre
    23:52 modifié #25
    C'est toujours bon à  prendre... La méthode de Bru fonctionne parfaitement, il ne me reste plus qu'à  finir 2 ou 3 choses et le module d'importation est terminé.
    Sinon, j'ai un problème avec les tags, ça ne fonctionne qu'avec des mots clés en minuscules...
    J'ai choisi cette option en accord avec ceci : http://www.streit.cc/dive/udcf_doc_eng.html mais le fichier joint en exemple sur le même site utilise des mots en majuscules, quelle option choisir ?
  • BruBru Membre
    23:52 modifié #26
    dans 1147545487:

    Sinon, j'ai un problème avec les tags, ça ne fonctionne qu'avec des mots clés en minuscules...
    J'ai choisi cette option en accord avec ceci : http://www.streit.cc/dive/udcf_doc_eng.html mais le fichier joint en exemple sur le même site utilise des mots en majuscules, quelle option choisir ?


    XML est case-sensitive... C'est la norme !

    .
  • VeillardVeillard Membre
    23:52 modifié #27
    Je le pensais aussi mais je ne comprends pas pourquoi ça ne fonctionne pas dès que je mets des majuscules...
  • AliGatorAliGator Membre, Modérateur
    23:52 modifié #28
    Ben parce que comme le dit Bru c'est case-sensitive !

    Regarde dans le DTD ou la norme UDCF si les tags sont en majuscules ou en minuscule dans les docs UDCF.
    Si par exemple dans la norme udcf les tags sont en minuscule, et que tu as des documents avec les tags en majuscules, c'est que ce ne sont pas des documents valides : ils ne sont pas conformes à  la norme et ne sont pas valides par rapport à  leur DTD.
    Donc normalement tu ne devrais pas en tenir compte voire les ignorer.

    XML a justement été construit en se fixant des règles très strictes absolument à  respecter, poour éviter aussi toutes les divergences qu'il y a peu avoir en HTML avec les diverses variantes et les pb de navigateurs etc. Donc en XML c'est très strict mais ça a l'avantage d'être sûr que tout le monde se comprend pour éviter que tu aies à  gérer 15 000 cas. Donc on respecte la norme et un point c'est tout.

    Si y'en a qui te fournissent des documents soit-disant udcf mais qui ne respectent pas la norme car mettent des tags en majuscules au lieu de minuscule (ou vice-versa), alors tu n'as pas à  savoir ouvrir ces documents, c'est à  eux de les rendre "udcf-compliant".
  • VeillardVeillard Membre
    23:52 modifié #29
    Le problème c'est que l'auteur du site traitant de l'UDCF utilise les deux casses dans ses exemples...

    &lt;PROFILE UDCF=&quot;1&quot;&gt;<br />&lt;!-- This file was generated by &#39;eonconvert&#39; --&gt;<br />&lt;!-- Converted for: streit@kurgan.mayn.de --&gt;<br />&lt;!-- Date: Thu Dec 30 19:07:57 MET 1999 --&gt;<br />&lt;UNITS&gt;Metric&lt;/UNITS&gt;<br />&lt;DEVICE&gt;<br /> &lt;VENDOR&gt;Suunto&lt;/VENDOR&gt;<br /> &lt;MODEL&gt;EON&lt;/MODEL&gt;<br /> &lt;VERSION&gt;1&lt;/VERSION&gt;<br />&lt;/DEVICE&gt;<br />&lt;ADDINFO&gt;<br /> &lt;PERSINFO&gt;+49-931-123456&nbsp; &nbsp; &nbsp; &lt;/PERSINFO&gt;<br /> &lt;TOTALDIVES&gt;60&lt;/TOTALDIVES&gt;<br /> &lt;SERIALID&gt;11.22.33&lt;/SERIALID&gt;<br />&lt;/ADDINFO&gt;<br />&lt;REPGROUP&gt;
    


    C'est le même exemple qu'a donné Bru...

    et plus loin, il écrit ceci :

    &lt;profile udcf=&quot;1&quot;&gt;<br />&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &lt;!-- here statements about units used and manufacturer --&gt;<br />&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &lt;repgroup&gt;<br />&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &lt;dive&gt;<br />&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &lt;!-- here statements about place, if known&nbsp; --&gt;<br />&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &lt;!-- date April 6th, 1999 --&gt;<br />&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &lt;date&gt;&lt;year&gt;1999&lt;/year&gt;&lt;month&gt;4&lt;/month&gt;&lt;day&gt;6&lt;/day&gt;&lt;/date&gt;<br />&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &lt;!-- here more statements --&gt;<br />&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &lt;/dive&gt;<br />&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &lt;!-- following statements --&gt;<br />&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &lt;/profile&gt;
    


    donc, logiquement c'est bien du case-insensitive.
  • AliGatorAliGator Membre, Modérateur
    mai 2006 modifié #30
    Erreur !

    Moi je dirais plutôt : "donc logiquement le mec qui met les udcf sur le site ne respecte pas la norme XML".

    XML est case-sensitive, ça j'en suis sûr et certain. Bru te le confirmera aussi. Et google aussi :P

    [EDIT]Ignorer la partie qui va suivre sur les solutions alternatives, je me corrige en page 3 dans mon prochain post[/EDIT]

    Bon au grand grand pire tu peux récupérer le tableau des <dive> et celui des <DIVE> (en espérant qu'il n'aille pas jusqu'à  utiliser des tags "DivE" ou des variantes du genre, là  ce serait le pire) et merger (fusionner) les deux NSArray ensemble dans un seul NSArray pour le traiter.
    Mais pour moi le mieux ce serait d'écrire à  l'auteur du site d'où tu chopes tes udcf et lui dire que le XML est case-sensitive et qu'il faut qu'il se décide sur la casse de ses tags.

    Une autre solution pour contourner le non-respect de la norme XML par l'auteur de ton site sur udcf, c'est de convertir tout ton XML en minuscules (tu le charges dans une NSString avec stringWithContentsOfFile:, puis tu fais récupères la même chaà®ne en minuscule avec "lowercaseString"). Mais le problème c'est que ça va convertir aussi l'intérieur des tags (les textes "bruts") et non pas que les tags.

    Ou alors tu utilises NSXMLParser qui fait du parsing évènementiel et appelle des méthodes de delegate à  l'ouverture des tags, et comme ça pour savoir si c'est un tag "dive" tu peux faire un caseInsensitiveCompare... Mais bon ça fait bcp de chamboulement pour si peu.

    Donc je serais toi je mettrais un petit mot à  ce gars sur son site pour lui dire de choisir entre majuscules et minuscules pour ses tags car sinon il ne respecte pas la norme XML.
  • VeillardVeillard Membre
    23:52 modifié #31
    Je crois que je suis fatigué, je lisais dans les posts "insensitive" au lieu de "sensitive", je comprends mieux l'erreur. Il faut maintenant rechercher la bonne casse.

    Merci à  tous les deux pour votre patience...
Connectez-vous ou Inscrivez-vous pour répondre.