objective c - Ejemplo simple de NSXMLParser
objective-c swift (3)
Aquí hay una versión Swift del código Objective-C original a continuación.
Fue construido y probado usando XCode 7.3. Al escribir al delegado, me pareció muy útil copiar los prototipos de función de la documentación. Vale la pena señalar que Swift es actualmente un objetivo en movimiento bastante rápido.
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")
}
}
La mayoría de los ejemplos de cómo invocar NSXMLParser están contenidos en proyectos complejos que involucran aplicaciones. ¿Qué aspecto tiene un ejemplo simple que demuestra las devoluciones de llamada?
Como parte de la exploración de NSXMLParser, creé el siguiente código realmente simple.
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
Lo publiqué con la esperanza de que ayude a alguien más.
Ejemplo de Swift 4: análisis del archivo 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
}
}
}
Uso:
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.