Libxml2 XML DOM Analyse avec XPathQuery

J'essaye d'analyser le fichier xml suivant:


    Aabach - Hitzkirch
    11.11.2013
    18:00
    2.02
    1.93



    Aach - Salmsach
    11.11.2013
    18:00
    406.47
    406.64

Je vais lire les valeurs de l'élément si l'attribut "StrNr" est égal à "2416". Mon code est:

NSURL *url = [NSURL URLWithString:@"http://www.hydrodaten.admin.ch/lhg/SMS.xml"];
NSData *webData = [NSData dataWithContentsOfURL:url options:NSUTF8StringEncoding error:nil];
TFHpple *parser = [TFHpple hppleWithData:webData isXML:YES];
NSString *xPathQuery = @"//AKT_Data/MesPar";
NSArray *arrayPaser= [parser searchWithXPathQuery:xPathQuery];

NSMutableArray *arrayName = [[NSMutableArray alloc] initWithCapacity:0];
NSMutableArray *arrayDatum = [[NSMutableArray alloc] initWithCapacity:0];
NSMutableArray *arrayWertDt24h = [[NSMutableArray alloc] initWithCapacity:0];


for (TFHppleElement *element in arrayPaser) {
    if ([[element firstChild] content]!=nil) {
        NSDictionary *attribute=[element attributes];

        NSString *string= [NSString stringWithFormat:@"%@",[attribute valueForKey:@"StrNr"]];

        if ([string isEqualToString:@"2416"]) {

            arrayName addObject:[element ??????];
            arrayDatum addObject:[element ?????];
            arrayWertDt24h addObject:[element ????];
        }

Je ne sais pas comment j'obtiens les valeurs de l'élément?

0

1 Réponses

J'ai une solution qui implique l'utilisation de NSXMLParser intégré et de quelques méthodes NSXMLParserDelegate.

Commençons par sous-classer NSObject et créons une classe parser. Voici le .h:

#import 

@interface XMLParser : NSObject

- (id)initWithData:(NSData *)data;
- (BOOL)parse;

@end

Ici, vous pouvez voir que nous allons nourrir cet objet les données que vous souhaitez analyser et après cela, nous pouvons lui dire d'analyser. La méthode parse est simplement un wrapper autour de la méthode d'analyse NSXMLParser que vous verrez dans un instant.

Une extension de classe est l'endroit où nous allons ajouter les propriétés privées que nous utiliserons pour gérer les données que nous analysons. Il apparaît comme suit:

@interface XMLParser ()


@property (nonatomic, strong) NSData *data;
@property (nonatomic, strong) NSXMLParser *parser;
@property (nonatomic, strong) NSMutableDictionary *objectDict;
@property (nonatomic, strong) NSMutableString *elementDataString;
@property (nonatomic, strong) NSMutableDictionary *wertTwo;
@property (nonatomic, assign, getter = isParsingWertTwo) BOOL parsingWertTwo;

@end

Les propriétés data </​​code> et parser s'expliquent d'elles-mêmes. La propriété objectDict est ce que nous allons utiliser pour stocker les données que vous cherchez à analyser à partir de ce XML. L'elementDataString contient les caractères que l'analyseur trouve entre les balises d'élément. Nous avons une propriété wertTwo et un drapeau pour indiquer quand nous analysons le second élément Wert. C'est ainsi que nous pouvons nous assurer de saisir les attributs de ce deuxième élément Wert.

Le début de l'implémentation apparaît comme suit:

@implementation XMLParser

- (id)initWithData:(NSData *)data
{
    self = [super init];
    if (self) {
        self.data = data;
        self.parser = [[NSXMLParser alloc] initWithData:data];
        self.parser.delegate = self;
        self.objectDict = [@{} mutableCopy];
        self.wertTwo = [@{} mutableCopy];
    }
    return self;
}

- (BOOL)parse
{
    return [self.parser parse];
}

Comme vous pouvez le voir à partir de l'initialiseur, nous configurons les objets dont nous avons besoin avec les données et l'analyseur pour effectuer l'analyse proprement dite. La méthode d'analyse comme je l'ai mentionné enveloppe simplement la méthode parse de la classe NSXMLParser. Il retourne effectivement un BOOL et c'est pourquoi j'ai choisi de le renvoyer ici aussi. Nous avons défini self en tant que délégué de l'analyseur. Nous devons donc implémenter quelques méthodes dans le protocole délégué afin d'obtenir les données nécessaires. Les méthodes de délégué apparaissent comme suit:

#pragma mark - NSXMLParserDelegate

- (void)parser:(NSXMLParser *)parser
didStartElement:(NSString *)elementName
  namespaceURI:(NSString *)namespaceURI
 qualifiedName:(NSString *)qName
    attributes:(NSDictionary *)attributeDict
{
    if ([elementName isEqualToString:@"MesPar"]) {

       //Get the value from the attribute dict of the MesPar element
        NSString *value = attributeDict[@"StrNr"];

       //Compare whether the value is equal to the desired value
        if ([value isEqualToString:@"2416"]) {

           //if the value is equal, add the attribute dict to the object dict
            [self.objectDict addEntriesFromDictionary:attributeDict];

            return;
        }
    }

   //If the element is Wert AND there is an attribute named dt we know this is the second Wert element
    if ([elementName isEqualToString:@"Wert"] && attributeDict[@"dt"]) {

       //add the attribute element to the wertTwo dict
        [self.wertTwo addEntriesFromDictionary:attributeDict];

       //Set the parsing flag to YES so we know where we are in the delegate methods
        self.parsingWertTwo = YES;

        return;
    }
}

- (void)parser:(NSXMLParser *)parser
 didEndElement:(NSString *)elementName
  namespaceURI:(NSString *)namespaceURI
 qualifiedName:(NSString *)qName
{
   //if this is the Name element, set the element data in the object dict
    if ([elementName isEqualToString:@"Name"]) {
        [self.objectDict setObject:[self.elementDataString copy] forKey:@"name"];

       //set the data to nil since it will be reset by a delegate method for the next element
        self.elementDataString = nil;

        return;
    }

    if ([elementName isEqualToString:@"Datum"]) {
        [self.objectDict setObject:[self.elementDataString copy] forKey:@"datum"];

       //set the data to nil since it will be reset by a delegate method for the next element
        self.elementDataString = nil;

        return;
    }

    if ([elementName isEqualToString:@"Zeit"]) {
        [self.objectDict setObject:[self.elementDataString copy] forKey:@"zeit"];

       //set the data to nil since it will be reset by a delegate method for the next element
        self.elementDataString = nil;

        return;
    }


    if ([elementName isEqualToString:@"Wert"]) {

       //Checks to see if this is the Wert element AND that we are parsing the second element
        if (self.isParsingWertTwo) {
            [self.wertTwo setObject:[self.elementDataString copy] forKey:@"wertTwoString"];

           //set the wertTwo dict for the key wertTwo in the object dict
           //this allows us to pull out this info for the key wertTwo and includes the attribute of dt along with the elementDataString
            [self.objectDict setObject:[self.wertTwo copy] forKey:@"wertTwo"];

           //set the data to nil since it will be reset by a delegate method for the next element
            self.elementDataString = nil;

            return;
        }
        else{
            [self.objectDict setObject:[self.elementDataString copy] forKey:@"wertOne"];

           //set the data to nil since it will be reset by a delegate method for the next element
            self.elementDataString = nil;

            return;
        }
    }
}

- (void)parserDidEndDocument:(NSXMLParser *)parser
{
   //You do not have to implement this but if you'd like here you can access `self.objectDict` which should have a representation of your xml you're looking to parse
}


- (void)parser:(NSXMLParser *)parser foundCharacters:(NSString *)string
{
   //Append the foundCharacters (in between the element tags) to the data string
    [self.elementDataString appendString:string];
}

Le code est commenté sur ce qui se passe réellement mais en bref, l'analyseur notifie le délégué, self dans ce cas quand certaines choses se produisent comme quand il rencontre un élément ou lorsqu'il trouve des caractères . Une chose à garder à l'esprit est que la propriété elementDataString doit être chargée paresseusement et c'est ce que nous faisons:

// lazy loads the elementDataString if it is nil
// it will be set to nil after each time it is set in a dict
// this is why we copy it when we add it to the dict
- (NSMutableString *)elementDataString
{
    if (!_elementDataString) {
        _elementDataString = [NSMutableString string];
    }
    return _elementDataString;
}

Il y a plusieurs choses que je n'ai pas abordées telles que les erreurs dans l'analyse ou les méthodes de délégué supplémentaires qui pourraient vous intéresser. C'est une solution particulière qui utilise des classes intégrées plutôt que de s'appuyer sur une bibliothèque tierce.

1
ajouté