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.
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.
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.
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")
}
}
#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>