web-dev-qa-db-fra.com

Exemple simple NSXMLParser

La plupart des exemples sur la façon d'invoquer NSXMLParser sont contenus dans des projets complexes impliquant des applications. À quoi ressemble un exemple simple qui illustre les rappels.

44
TJA

Dans le cadre de l'exploration de NSXMLParser, j'ai créé le code très simple suivant.

main.m

int main(int argc, const char * argv[])
{

    @autoreleasepool {
        NSLog(@"Main Started");

        NSError *error = nil;

        // Load the file and check the result
        NSData *data = [NSData dataWithContentsOfFile:@"/Users/Tim/Documents/MusicXml/Small.xml"
                                          options:NSDataReadingUncached
                                            error:&error];
        if(error) {
            NSLog(@"Error %@", error);

            return 1;
        }


        // Create a parser and point it at the NSData object containing the file we just loaded
        NSXMLParser *parser = [[NSXMLParser alloc] initWithData:data];

        // Create an instance of our parser delegate and assign it to the parser
        MyXmlParserDelegate *parserDelegate = [[MyXmlParserDelegate alloc] init];
        [parser setDelegate:parserDelegate];

        // Invoke the parser and check the result
        [parser parse];
        error = [parser parserError];
        if(error)
        {
            NSLog(@"Error %@", error);

            return 1;
        }

        // All done
        NSLog(@"Main Ended");
    }
    return 0;
}

MyXmlParserDelegate.h

#import <Foundation/Foundation.h>

@interface MyXmlParserDelegate : NSObject <NSXMLParserDelegate>

@end

MyXmlParserDelegate.m

#import "MyXmlParserDelegate.h"

@implementation MyXmlParserDelegate

- (void) parserDidStartDocument:(NSXMLParser *)parser {
    NSLog(@"parserDidStartDocument");
}

- (void)parser:(NSXMLParser *)parser didStartElement:(NSString *)elementName namespaceURI:(NSString *)namespaceURI qualifiedName:(NSString *)qName attributes:(NSDictionary *)attributeDict {
    NSLog(@"didStartElement --> %@", elementName);
}

-(void) parser:(NSXMLParser *)parser foundCharacters:(NSString *)string {
    NSLog(@"foundCharacters --> %@", string);
}

- (void)parser:(NSXMLParser *)parser didEndElement:(NSString *)elementName namespaceURI:(NSString *)namespaceURI qualifiedName:(NSString *)qName {
    NSLog(@"didEndElement   --> %@", elementName);
}

- (void) parserDidEndDocument:(NSXMLParser *)parser {
    NSLog(@"parserDidEndDocument");
}
@end

Je l'ai posté dans l'espoir qu'il aide quelqu'un d'autre.

13
TJA

Exemple de Swift 4 - Analyse du fichier Xib.

import Foundation

class XMLTransformer: NSObject {

   private let parser: XMLParser
   private var stack = [Node]()
   private var tree: Node?

   init(data: Data) {
      parser = XMLParser(data: data)
      super.init()
      parser.delegate = self
   }
}

extension XMLTransformer {

   func transform() throws -> Node? {
      parser.parse()
      if let e = parser.parserError {
         throw e
      }
      assert(stack.isEmpty)
      assert(tree != nil)
      return tree
   }

}

extension XMLTransformer: XMLParserDelegate {

   func parser(_ parser: XMLParser, didStartElement elementName: String, namespaceURI: String?, qualifiedName qName: String?, attributes attributeDict: [String : String] = [:]) {
      guard let tag = Tag(rawValue: elementName) else {
         return
      }
      let node = Node(tag: tag, attributes: attributeDict, nodes: [])
      stack.append(node)
   }

   func parser(_ parser: XMLParser, didEndElement elementName: String, namespaceURI: String?, qualifiedName qName: String?) {
      guard let tag = Tag(rawValue: elementName) else {
         return
      }
      let lastElement = stack.removeLast()
      assert(lastElement.tag == tag)
      if let last = stack.last {
         last.nodes += [lastElement]
      } else {
         tree = lastElement
      }
   }
}

extension XMLTransformer {

   enum Tag: String {
      case document
      case objects
      case tableViewCell, tableViewCellContentView
      case subviews
      case mapView
      case constraints, constraint
      case connections, outlet
   }
}

extension XMLTransformer {

   class Node {

      let tag: Tag
      let attributes: [String : String]
      var nodes: [Node]

      init(tag: Tag, attributes: [String : String], nodes: [Node] = []) {
         self.tag = tag
         self.attributes = attributes
         self.nodes = nodes
      }
   }
}

Usage:

let data = try xib(named: "MapTableViewCell")
let c = XMLTransformer(data: data)
let tree = try c.transform() // Here you have parsed XML in a Tree representation.
0
Vlad

Voici une version Swift du code Objective-C original ci-dessous.

Il a été construit et testé à l'aide de XCode 7.3. En écrivant au délégué, j'ai trouvé assez pratique de copier les prototypes de fonction de la documentation. Il convient de noter que Swift est actuellement une cible qui évolue assez rapidement.

main.Swift

import Foundation

// Let's go
print("Main: Started")

// Try to load the file. Display the description of the error if one occurs
var xmlData : NSData
do {
    xmlData = try NSData(contentsOfFile: "/Users/amt/Documents/TestXml/Test.xml",
                         options: .DataReadingMappedIfSafe)
}
catch let error as NSError {
    print("Main: \(error.description)")

    exit(1)
}

// Create a parser and point it at the NSData object containing
// the file we just loaded
var parser : NSXMLParser! = NSXMLParser(data: xmlData)

// Create a parser delegate object and assign it to the parser
// Beware the "weak" reference and don't try to combine the two lines
// of code into one unless you like EXC_BAD_ACCESS exceptions
var parserDelegate : MyXmlParserDelegate = MyXmlParserDelegate()
parser.delegate = parserDelegate

// This example also illustrates some of the namespace functions defined in
// the delegate protocol so enable namespace reporting to see them invoked
parser.shouldReportNamespacePrefixes = true

// Parse the document
if !parser.parse() {
    // If parse() returned false then an error occurred so display is location
    // and details
    let error = parser.parserError
    let line = parser.lineNumber
    let col = parser.columnNumber
    print("Parsing failed at \(line):\(col): \(error?.localizedDescription)")
}

// All done
print("Main: Ended")
exit(0)

MyXmlParserDelegate.Swift

import Foundation

class MyXmlParserDelegate:NSObject, NSXMLParserDelegate {

    @objc func parserDidStartDocument(parser: NSXMLParser) {
        print("parserDidStartDocument")
    }

    @objc func parser(parser: NSXMLParser, didStartElement elementName: String,
               namespaceURI: String?, qualifiedName qName: String?,
               attributes attributeDict: [String : String]) {
        print("didStartElement       --> \(elementName)")
    }

    @objc func parser(parser: NSXMLParser, foundCharacters string: String) {
        print("foundCharacters       --> \(string)")
    }

    @objc func parser(parser: NSXMLParser, didEndElement elementName: String,
               namespaceURI: String?, qualifiedName qName: String?) {
        print("didEndElement         --> \(elementName)")
    }

    @objc func parser(parser: NSXMLParser, didStartMappingPrefix prefix: String,
               toURI namespaceURI: String) {
        print("didStartMappingPrefix --> Prefix: \(prefix) toURI: \(namespaceURI)")
    }

    @objc func parser(parser: NSXMLParser, didEndMappingPrefix prefix: String) {
        print("didEndMappingPrefix   --> Prefix: \(prefix)")
    }

    @objc func parserDidEndDocument(parser: NSXMLParser) {
        print("parserDidEndDocument")
    }
}
0
TJA
#import <Cocoa/Cocoa.h>

@interface AppDelegate : NSObject <NSApplicationDelegate, NSXMLParserDelegate>
@property (nonatomic, strong) NSMutableDictionary *dictXML;
@property (nonatomic,strong) NSMutableArray *arrOfUpdateDictsByVersion;
@property (nonatomic,strong) NSString *strElementBeingParsed;
@property (nonatomic,strong) NSString *strElementFinishedParsing;

@end


#import "AppDelegate.h"

@interface AppDelegate ()
@property (weak) IBOutlet NSWindow *window;
@end

@implementation AppDelegate

@synthesize dictXML;
@synthesize arrOfUpdateDictsByVersion;

@synthesize strElementBeingParsed;
@synthesize strElementFinishedParsing;


- (void)applicationDidFinishLaunching:(NSNotification *)aNotification {
    // Insert code here to initialize your application

    [self initializeTheArray];
    [self startParsingXML];
}

-(void)initializeTheArray{
    self.dictXML = [[NSMutableDictionary alloc] init];
    self.arrOfUpdateDictsByVersion = [[NSMutableArray alloc] init];
}

-(void)startParsingXML{
//    NSXMLParser *xmlparser = [[NSXMLParser alloc] initWithContentsOfURL:[NSURL URLWithString:@"http://cdn.example.com/databaseupdate.xml"]];
    NSXMLParser *xmlparser = [[NSXMLParser alloc] initWithContentsOfURL:[NSURL fileURLWithPath:@"/Users/vkrmsinha/Desktop/xmlParse.xml"]];
    [xmlparser setDelegate:self];
    [xmlparser parse];
}

- (void)parser:(NSXMLParser *)parser didStartElement:(NSString *)elementName namespaceURI:(NSString *)namespaceURI qualifiedName:(NSString *)qName attributes:(NSDictionary *)attributeDict;
{
    // initial tag comes in here
    self.strElementBeingParsed = elementName;
    /*if([elementName isEqualToString:@"Version"]){

    }
    else if ([elementName isEqualToString:@"Update"]){

    }*/
}

- (void)parser:(NSXMLParser *)parser foundCharacters:(NSString *)string;
{

    if(([string rangeOfCharacterFromSet:[NSCharacterSet newlineCharacterSet]].location != NSNotFound) && ![self.strElementBeingParsed isEqualToString:@"Update"])
        return;

    // middle part from between the start and end tags comes here
    if ([self.strElementBeingParsed isEqualToString:@"Update"]){
        NSMutableDictionary *dictUpdate = [NSMutableDictionary dictionary];
        [self.arrOfUpdateDictsByVersion addObject:dictUpdate];
    }
    else if ([self.strElementBeingParsed isEqualToString:@"UpdateType"]){
        NSMutableDictionary *dictUpdate = [self.arrOfUpdateDictsByVersion lastObject];
        NSMutableDictionary *dictUpd = [NSMutableDictionary dictionary];
        [dictUpd setValue:string forKey:@"UpdateType"];
        [dictUpdate setValue:dictUpd forKey:@"update"];
    }
    else if([self.strElementBeingParsed isEqualToString:@"Version"]){
        NSMutableDictionary *dictUpdate = [self.arrOfUpdateDictsByVersion lastObject];
        // WARNING: ASK IF NO TWO VERSION WILL BE SAME IN FUTURE
        [dictUpdate setValue:string forKey:@"version"];
    }
    else if ([self.strElementBeingParsed isEqualToString:@"FileName"]){
        NSMutableDictionary *dictUpdate = [self.arrOfUpdateDictsByVersion lastObject];
        NSMutableDictionary *dict = [dictUpdate objectForKey:@"update"];
        [dict setValue:string forKey:@"FileName"];
    }
    else if ([self.strElementBeingParsed isEqualToString:@"Hash"]){
        NSMutableDictionary *dictUpdate = [self.arrOfUpdateDictsByVersion lastObject];
        NSMutableDictionary *dict = [dictUpdate objectForKey:@"update"];
        [dict setValue:string forKey:@"Hash"];
    }
    else if ([self.strElementBeingParsed isEqualToString:@"DownloadURL"]){
        NSMutableDictionary *dictUpdate = [self.arrOfUpdateDictsByVersion lastObject];
        NSMutableDictionary *dict = [dictUpdate objectForKey:@"update"];
        [dict setValue:string forKey:@"DownloadURL"];
    }
    else if ([self.strElementBeingParsed isEqualToString:@"Size"]){
        NSMutableDictionary *dictUpdate = [self.arrOfUpdateDictsByVersion lastObject];
        NSMutableDictionary *dict = [dictUpdate objectForKey:@"update"];
        [dict setValue:string forKey:@"Size"];
    }

}

- (void)parser:(NSXMLParser *)parser didEndElement:(NSString *)elementName namespaceURI:(NSString *)namespaceURI qualifiedName:(NSString *)qName;
{
    // ending of tag comes in here
    self.strElementFinishedParsing = elementName;
    if([elementName isEqualToString:@"Update"]){
        [self.arrOfUpdateDictsByVersion sortUsingDescriptors:[NSArray arrayWithObjects:[NSSortDescriptor sortDescriptorWithKey:@"self.version" ascending:YES], nil]];
        NSLog(@"%@", [self.arrOfUpdateDictsByVersion lastObject]);

    }
    if([elementName isEqualToString:@"UpdateDetails"]){
        NSMutableDictionary *dict = [NSMutableDictionary dictionary];
        [dict setValue:[[self.arrOfUpdateDictsByVersion lastObject] objectForKey:@"version"] forKey:@"latestVer"];
        [dict setValue:[[self.arrOfUpdateDictsByVersion firstObject] objectForKey:@"version"] forKey:@"oldestVer"];
        [dict setValue:self.arrOfUpdateDictsByVersion forKey:@"arrOfUpdsByVer"];
        NSLog(@"%@", dict);
    }

}

- (void)applicationWillTerminate:(NSNotification *)aNotification {
    // Insert code here to tear down your application
}


<UpdateDetails xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:xsd="http://www.w3.org/2001/XMLSchema">
   <DatabaseUpdates>
    <Update>
     <UpdateType>CompleteDatabase</UpdateType>
     <Version>1</Version>
     <FileName>1completedatabase.Zip</FileName>
     <Hash>ad94431d2fe4cd60eb3347fadaa45d88</Hash>
     <DownloadURL>
      http://www.example.com/download/new.xml
     </DownloadURL>
     <Size>2367008</Size>
    </Update>
</DatabaseUpdates>
</UpdateDetails>
0
Vikram Sinha