NSXMLParser 解析 XML

本文参考自iOS_Cookbook(下面只列出关键代码,如果看不懂有什么建议希望大家能提出来)

创建一个简单的 XML文件,包含如下内容(把他命名为 xmlFile.xml,然后添加到你的工程中):

<?xml version="1.0" encoding="UTF-8"?> 
<root>
    <person id="1">
        <firstName>Anthony</firstName>
        <lastName>Robbins</lastName>
        <age>51</age>
    </person>
    <person id="2">
        <firstName today="just study">Richard</firstName>
        <lastName words="This is just a joke">Branson</lastName>
        <age>61</age>
    </person>
</root>


为 XML对象创建一个对象模型。下面我们定义一个对象来代表 XML element,类名叫做 XMLElement

#import <Foundation/Foundation.h>

@interface XMLElement : NSObject

@property (nonatomic,retain) NSString *name;
@property (nonatomic,retain) NSString *text;
@property (nonatomic,retain) NSDictionary *attributes;
@property (nonatomic,retain) NSMutableArray *subElements;
@property (nonatomic,retain) XMLElement *parent;
@end


实现 XMLElement类:

#import "XMLElement.h"

@implementation XMLElement
@synthesize name;
@synthesize text;
@synthesize attributes;
@synthesize subElements;
@synthesize parent;

- (void)dealloc
{
    [name release];
    [text release];
    [attributes release];
    [subElements release];
    [parent release];
    [super dealloc];
}

/*
    我只想当访问 subElements 数组的时候,如果该数组是 nil,才进行初始化。因此我把这 个属性的内存分配和初始化代码放到了它的 getter 方法中。如果说一个 XML element 没有子 elements,那么我们永远都不会使用到这个属性,因此这里也就不会为那个 element 分配内 存和进行初始化工作。这种技术叫做 lazy allocation。
 */
- (NSMutableArray *)subElements
{
    if (subElements == nil) {
        subElements = [[NSMutableArray alloc] init];
    }
    return subElements;
}
@end

 
新建一个类,通过实现 NSXMLParser的协议来进行 XML内容的解析
在.h文件中添加一下属性:

//定义一个 NSXMLParser 类型的属性
@property (nonatomic,retain) NSXMLParser *xmlParser;

/*
    currentElementPoint 代表此刻在 XML 文件结构中,正在解析的 XML element,因此, 可以上移或者下移这个结构,来当做我们解析的文件内容。它是一个简单的指针,反之, rootElement 总是指向 XML 文件的 root element
 */
@property (nonatomic,retain) XMLElement *currentElementPoint;

@property (nonatomic,retain) XMLElement *rootElement;

 
在.m文件中实现:

@synthesize xmlParser;
@synthesize window = _window;
@synthesize currentElementPoint;
@synthesize rootElement;
- (void)dealloc
{
    [_window release];
    [xmlParser release];
    [currentElementPoint release];
    [rootElement release];
    [super dealloc];
}

- (BOOL)application:(UIApplication *)application didFinishLaunchingWithOptions:(NSDictionary *)launchOptions
{
    self.window = [[[UIWindow alloc] initWithFrame:[[UIScreen mainScreen] bounds]] autorelease];
    // Override point for customization after application launch.
    self.window.backgroundColor = [UIColor whiteColor];
    
    /*
        把文件内容读取到一个 NSData 实例对象中,然后使用 initWithData:来初始化我们 的 XML parser,并把我们从 xml 文件中读取出来的数据传递进去。之后我们可以调用 XML parser 的 parse 方法来开始解析处理。这个方法会阻塞当前线程,直至解析处理结束。如果 你需要解析的 XML 文件非常大,强烈建议使用一个全局的 dispatch 队列来进行解析。
     */
    NSString *xmlPath = [[NSBundle mainBundle] pathForResource:@"xmlFile" ofType:@"xml"];
    NSData *data = [[NSData alloc] initWithContentsOfFile:xmlPath];
    xmlParser = [[NSXMLParser alloc] initWithData:data];
    [data release];
    self.xmlParser.delegate = self;
    if ([self.xmlParser parse]) {
        NSLog(@"The xml is parsed!");
    }else
    {
        NSLog(@"The xml is not parsed!");
    }
    [self.window makeKeyAndVisible];
    return YES;
}

/*
 parserDidStartDocument:
 解析开始的时候调用该方法。
 parserDidEndDocument:
 解析结束的时候调用该方法。
 parser:didStartElement:namespaceURI:qualifiedName:attributes:
 在 XML document 中,当解析器在解析的时候遇到了一个新的 element 时会被调用该
 方法。
 parser:didEndElement:namespaceURI:qualifiedName:
 当前节点结束之后会调用。
 parser:foundCharacters:
 当解析器在解析文档内容的时候被调用。
 */

- (void)parserDidStartDocument:(NSXMLParser *)parser
{
    //重置属性
    self.currentElementPoint = nil;
    self.rootElement = nil;
}

- (void)parser:(NSXMLParser *)parser didStartElement:(NSString *)elementName namespaceURI:(NSString *)namespaceURI qualifiedName:(NSString *)qName attributes:(NSDictionary *)attributeDict
{
    //如果 root element 没有被创建,会被创建,并且开始解析一个新的 element,我 们会计算它在 XML 结构中的位置,并在当前 element 中添加一个新的 element。
    if (self.rootElement == nil) {
        self.rootElement = [[XMLElement alloc] init];
        self.currentElementPoint = self.rootElement;
    }else
    {
        XMLElement *newElement = [[XMLElement alloc] init];
        newElement.parent = self.currentElementPoint;
        [self.currentElementPoint.subElements addObject:newElement];
        self.currentElementPoint = newElement;
        [newElement release];
    }
    self.currentElementPoint.name = elementName;
    self.currentElementPoint.attributes = attributeDict;
    NSLog(@"!!!!!!!!!!!!!%@ = %@",elementName,attributeDict);
}

/*
    这个方法将会在解析 element 的时 候调用多次,因此我们需要确保已经为多次进入该方法做好了准备。例如,如果一个 element 的文本有 4000 个字符长度,解析器在第一次解析时,最多只能解析 1000 个字符, 之后在解析当前 element 时,调用 parser:foundCharacters:方法,每次都是 1000,因此需要 4 次
 */

- (void) parser:(NSXMLParser *)parser foundCharacters:(NSString *)string
{
    if ([self.currentElementPoint.text length] > 0) {
        self.currentElementPoint.text = [self.currentElementPoint.text stringByAppendingString:string];
    }else
    {
        self.currentElementPoint.text = string;
    }
    NSLog(@"~~~~~~~~~~%@",string);
}

/*
    当 解析至某个 element 尾部时,会调用该方法。在这里,我们只需要把当前 element 指针指向 当前 element 的上一级
 */
- (void) parser:(NSXMLParser *)parser didEndElement:(NSString *)elementName namespaceURI:(NSString *)namespaceURI qualifiedName:(NSString *)qName
{
    self.currentElementPoint = self.currentElementPoint;
}

- (void) parserDidEndDocument:(NSXMLParser *)parser
{
    NSLog(@"<<<<<<<<<<<<<<<<%@",self.currentElementPoint.text);
    NSLog(@"<<<<<<<<<<<<<<<<%@",self.currentElementPoint);
    NSLog(@"<<<<<<<<<<<<<<<<%@",self.currentElementPoint.parent.subElements);
    NSLog(@"<<<<<<<<<<<<<<<<%@",self.rootElement.text);
    NSLog(@"<<<<<<<<<<<<<<<<%@",self.rootElement.subElements);


    NSLog(@"<<<<<<<<<<<<<<<<%@",self.currentElementPoint.parent.text);

}

 


  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 2
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 2
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值