Main Contents

[Objective-c] Application iPhone qui parse un fichier XML

juillet 28, 2011

Dans cet article nous allons voir comment parser un fichier Xml et récupérer les informations contenues. Dans un second article, on affichera ces infos dans un tableView. Merci à Medhi.N pour l’idée de ce tutorial! Allez C’est parti…

I) Introduction

Nous allons donc créer une application permettant de parser un fichier xml ce trouvant sur le net. Par exemple un fichier contenant des contacts.

1
2
3
4
5
6
7
8
9
<contacts>
   <Contact>
      <nom>Smith</nom>
      <prenom>Joe</prenom>
      <tel>321-123-4567</tel>
      <email>joe@smith.com</email>
   </Contact>
<!--...-->
</contacts>

Vous pouvez retrouver un exemple de fichier à cette adresse : http://www.jkraft.fr/testXml.xml

II) Contact

Commencons par créer un projet de type « Navigation-Based ». Notre fichier XML contenant des contacts nous allons créer une classe qui va gérer ces données. Ajouter une NSObject subclass, nommer la Contact.m et copiez ce code.

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
//Contact.h
#import <Foundation/Foundation.h>
 
@interface Contact : NSObject {
	NSString *prenom;
	NSString *nom;
	NSString *tel;
	NSString *email;
}
 
@property (nonatomic, retain) NSString *prenom;
@property (nonatomic, retain) NSString *nom;
@property (nonatomic, retain) NSString *tel;
@property (nonatomic, retain) NSString *email;
 
@end
1
2
3
4
5
6
7
8
9
10
11
//Contact.m
#import "Contact.h"
 
@implementation Contact
 
@synthesize prenom;
@synthesize nom;
@synthesize tel;
@synthesize email;
 
@end

Il n’y a rien de compliqué ici, on a crée une classe contact contenant 4 champs.

III) Parseur XML

Maintenant on va s’attaquer au parseur XML. C’est cette classe qui va ouvrir et fermer les balises et récupérer les données. Ajouter une 2eme classe de type NSObject du nom de XMLToObjectParser (par : Andrew).

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
//XMLToObjectParser.h
#import <Foundation/Foundation.h>
 
@interface XMLToObjectParser : NSObject <NSXMLParserDelegate> {
	NSString *className;
	NSMutableArray *items;
	NSObject *item; // stands for any class    
	NSString *currentNodeName;
	NSMutableString *currentNodeContent;
}
- (NSArray *)items;
- (id)parseXMLAtURL:(NSURL *)url 
		   toObject:(NSString *)aClassName 
		 parseError:(NSError **)error;
@end
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
//XMLToObjectParser.m
#import "XMLToObjectParser.h"
 
@implementation XMLToObjectParser
 
- (NSArray *)items
{
	return items;
}
 
- (id)parseXMLAtURL:(NSURL *)url 
		   toObject:(NSString *)aClassName 
		 parseError:(NSError **)error
{
	[items release];
	items = [[NSMutableArray alloc] init];
	className = aClassName;
	NSXMLParser *parser = [[NSXMLParser alloc] initWithContentsOfURL:url];
	[parser setDelegate:self];
	[parser parse];
 
	if([parser parserError] && error) {
		*error = [parser parserError];
	}
	[parser release];
	return self;
}
 
- (void)parser:(NSXMLParser *)parser
didStartElement:(NSString *)elementName
  namespaceURI:(NSString *)namespaceURI
 qualifiedName:(NSString *)qName
	attributes:(NSDictionary *)attributeDict
{
	NSLog(@"Open tag: %@", elementName);
	if([elementName isEqualToString:className]) {
		// create an instance of a class on run-time  
		item = [[NSClassFromString(className) alloc] init];
	}
	else {
		currentNodeName = [elementName copy];
		currentNodeContent = [[NSMutableString alloc] init];
	}
}
 
- (void)parser:(NSXMLParser *)parser 
 didEndElement:(NSString *)elementName
  namespaceURI:(NSString *)namespaceURI
 qualifiedName:(NSString *)qName
{
	NSLog(@"Close tag: %@", elementName);	
	if([elementName isEqualToString:className]) {
		[items addObject:item];		
		[item release];
		item = nil;
	}
	else if([elementName isEqualToString:currentNodeName]) {
		// use key-value coding     
		[item setValue:currentNodeContent forKey:elementName];
 
		[currentNodeContent release];
		currentNodeContent = nil;
 
		[currentNodeName release];
		currentNodeName = nil;
	}
}
 
- (void)parser:(NSXMLParser *)parser
foundCharacters:(NSString *)string
{   
	[currentNodeContent appendString:string];
}
 
- (void)dealloc
{
	[items release];
	[super dealloc];
}
 
@end

Cette classe va parcourir le xml et s’il trouve une balise portant le nom de la classe Contact, y copier les informations et retourner un objet de ce type.

IV) Code principal

Il ne reste plus qu’a faire fonctionner tout ca ensemble. Surtout n’oubliez les imports des 2 fichiers, XMLToObjectParser.h et Contact.h. Dans la classe principale de votre application,normalement RootViewController.m , il suffit d’ajouter ceci (dans mon cas dans le viewDidLoad).

1
2
3
4
5
6
7
8
9
10
11
12
- (void)viewDidLoad {
	NSURL *url = [NSURL URLWithString: @"http://www.jkraft.fr/testXml.xml"];
	XMLToObjectParser *myParser = [[XMLToObjectParser alloc] 
parseXMLAtURL:url toObject:@"Contact" parseError:nil];
 
	for(int i = 0; i < [[myParser items] count]; i++) {
		NSLog(@"Prénom: %@", [(Contact *)[[myParser items] objectAtIndex:i] prenom]);
	}
 
 
    [super viewDidLoad];
}

Une petite compilation et lors de l’exécution vous verrez apparaître dans la console toutes les ouvertures et fermetures des balises XML lors du parsage du fichier. Puis à la fin les prénoms lors du parcours de l’objet retourné.

Vous pouvez retrouver les fichiers sources ici : https://github.com/Jekar/jkraft-tuto

Catégorie(s): Développement, Iphone, Objective-C, Tutorial | Comments (25)

25 Comments