搜尋此網誌

2012年9月2日 星期日

iPhone开发技巧之网络篇(1)— 解析XML




  • 博主:易飞扬
  • 原文链接 : http://www.yifeiyang.net/iphone-web-development-techniques-of-the-chapter-1-parsing-xml/
  • 转载请保留上面文字。


  • iPhone开发技巧之网络篇(1)--- 解析XML

    开发 iPhone 上的网络应用程序的时候时常需要解析XML文档,比如web应用中的SOAP,REST,RSS信息等都是以XML为基础的。掌握XML解析的技术是很重要的。这里我将为大家介绍一下iPhone下解析XML的几种方法,并比较其性能。

    iPhone的XML库

    iPhone中标准的XML解析库有两个,分贝是libxml2和NSXMLParser。
    libxml2由Gnome项目开发、由于是MIT的开放协议,已经移植到许多的平台,在iPhone上也能使用。
    libxml2的特点是比较快。另外作为最基本的XML解析器,提供SAX和DOM解析。并且它对应的XML标准最多,比如名称空间、XPath、XPointer、HTML、XInclude、XSLT、XML Schema、Relax NG等。另外它是用C语言写的,比较高速。
    NSXMLParser是Cocoa中内含的XML解析器。它只提供了SAX解析的功能。因为是Cocoa的一部分、并且API是Objective-C的,所以与Mac系统兼容性强,使用也相对简单。

    XML解析与内存占用

    由于iPhone也是一种嵌入式设备,所以与其他的嵌入式设备一样,同样有内存,CPU等资源占用问题。所以在选择代码库的时候需要考虑性能与内存占用的问题。
    一般XML的解析器有SAX解析和DOM解析两种方式、相比之下SAX比较小巧精干,耗费的内存小。这是因为其设计思想与DOM完全不一样,一边得到数据一边解析,由回调的方式通知得到的数据,没有了DOM树的概念。
    现在的iPhone 3G搭载的RAM是128MB(3GS是256MB)。其中有iPhone OS本身使用的、还有根据用于使用情况不同,比如MP3,邮件,Safari等常驻程序等。基本上自己的程序可使用的内存大小是10MB左右的空间。
    开发XML解析程序的时候,需要注意到XML文件一般都比较大,如果使用DOM的话,消费的内存量肯定很多。所以在iPhone中上面这两种解析器只能使用SAX的解析方式。DOM方式只能在模拟器上使用(比如NSXMLDocument类),放到实际设备上就不管用了。(不过,在下面的章节中我将介绍一种使用DOM的第三方方法,对于小的XML文档还是值得一用的。)

    libxml2 vs NSXMLParser

    一般是使用libxml2的SAX解析器呢,还是使用NSXMLParser能,我们通过下面的SDK中附属的例子XMLPerformance来做个测试。
    相同的XML文档由网络下载,然后解析,比较的结果如下 :
    下载用时解析用时合计
    NSXMLParser1.419s5.525s7.134s
    libxml22.520s2.247s2.646s
    可以看到,libxml2比NSXMLParser快得多。这与它们处理的方式有些关系,NSXMLParser中调用SAX API的时候,参数是作为字符串传递的,需要先转换为NSString或者是NSDictionary对象,并且它不像libxml2那样是一边下载一边解析,需要整个文件下载完了才开始解析。所以说建议一般使用libxml2。

    NSXMLParser的例子

    解析的XML代码例子如下:
    1
    2
    3
    4
    5
    
    <?xml version="1.0" encoding="UTF-8"?>
    <users>
        <user name="hoge" age="20" />
        <user name="fuga" age="30" />
    </users>
    
    代码如下:
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    23
    24
    25
    26
    27
    28
    29
    30
    31
    32
    33
    34
    35
    36
    37
    38
    39
    40
    41
    42
    43
    44
    45
    46
    47
    48
    49
    
    static NSString *feedURLString = @"http://www.yifeiyang.net/test/test.xml";
    
    - (void)parserDidStartDocument:(NSXMLParser *)parser
    {
        // 解析开始时的处理
    }
    
    - (void)parseXMLFileAtURL:(NSURL *)URL parseError:(NSError **)error
    {
        NSXMLParser *parser = [[NSXMLParser alloc] initWithContentsOfURL:URL];
        [parser setDelegate:self];
        [parser setShouldProcessNamespaces:NO];
        [parser setShouldReportNamespacePrefixes:NO];
        [parser setShouldResolveExternalEntities:NO];
        [parser parse];
        NSError *parseError = [parser parserError];
        if (parseError && error) {
            *error = parseError;
        }
        [parser release];
    }
    
    - (void)parser:(NSXMLParser *)parser didStartElement:(NSString *)elementName namespaceURI:(NSString *)namespaceURI qualifiedName:(NSString *)qName attributes:(NSDictionary *)attributeDict
    {
        // 元素开始句柄
        if (qName) {
            elementName = qName;
        }
        if ([elementName isEqualToString:@"user"]) {
            // 输出属性值
            NSLog(@"Name is %@ , Age is %@", [attributeDict objectForKey:@"name"], [attributeDict objectForKey:@"age"]);
        }
    }
    
    - (void)parser:(NSXMLParser *)parser didEndElement:(NSString *)elementName namespaceURI:(NSString *)namespaceURI qualifiedName:(NSString *)qName
    {
        // 元素终了句柄
        if (qName) {
            elementName = qName;
        }
    }
    
    - (void)parser:(NSXMLParser *)parser foundCharacters:(NSString *)string
    {
        // 取得元素的text
    }
    
    NSError *parseError = nil;
    [self parseXMLFileAtURL:[NSURL URLWithString:feedURLString] parseError:&parseError];
    
    实际使用的时候除最后两行以外,所有的当如一个类中,最后两个是启动该类的代码。

    libxml2的例子

    项目中添加libxml
    首先需要将libxml添加到你的工程项目中。
    我们知道,当向项目中添加外部库的时候,如果是程序框架的,比如UIKit.framework,Foundation.framework等放在Sysytem/Library/Frameworks 目录下。SDK放在 /Developer/Platforms/iPhoneOS.platform/Developer/SDKs 目录下。
    但是由于libxml是UNIX的库、位于SDK文件夹的usr/lib下。头文件位于 usr/include 下。

    iphone libxml2
    在 libxml 目录下将 libxml2.2.dylib(或更高版本)添加到项目中。将头文件路径 usr/include/libxml2 也添加到包含路径中。
    以下是libxml2.2.dylib的路径
    /Developer/Platforms/iPhoneOS.platform/Developer/SDKs/iPhoneOS${VER}sdk/usr/lib/libxml2.2.dylib
    以下是头文件的路径
    /Developer/Platforms/iPhoneOS.platform/Developer/SDKs/iPhoneOS${VER}.sdk/usr/include/libxml2
    

    iphone libxml2
    libxml中的SAX解析器
    用过SAX解析器的朋友都知道,SAX就是事先登录一些处理函数,当XML解析到属性或要素的时候,回调登录的处理函数。
    以下是一个例子,DownloadOperation实现网络文件的下载,同时交给libxml2的SAX解析器处理:
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    23
    24
    
    // DownloadOperation.h
    #import <Foundation/Foundation.h>
    #import <libxml/tree.h>
    
    @interface DownloadOperation : NSOperation
    {
        NSURLRequest*           _request;
        NSURLConnection*        _connection;
        xmlParserCtxtPtr        _parserContext;
        BOOL                    _isExecuting, _isFinished;
    
        BOOL                    _isChannel, _isItem;
        NSMutableDictionary*    _channel;
        NSMutableDictionary*    _currentItem;
        NSMutableString*        _currentCharacters;
    }
    
    // Property
    @property (readonly) NSDictionary* channel;
    
    // Initialize
    - (id)initWithRequest:(NSURLRequest*)request;
    
    @end
    
    首先、#import了libxml/tree.h头文件。然后声明了一个 xmlParserCtxtPtr 变量作为解析器的实例。
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    23
    24
    25
    26
    27
    28
    29
    30
    31
    32
    33
    34
    35
    36
    37
    38
    39
    40
    41
    42
    43
    44
    45
    46
    47
    48
    49
    50
    51
    52
    53
    54
    55
    56
    57
    58
    59
    60
    61
    62
    63
    64
    65
    66
    67
    68
    69
    70
    71
    72
    73
    74
    75
    76
    77
    78
    79
    80
    81
    82
    83
    84
    85
    86
    87
    88
    89
    90
    91
    92
    93
    94
    95
    96
    97
    98
    99
    100
    101
    102
    103
    104
    105
    106
    107
    108
    109
    110
    111
    112
    113
    114
    115
    116
    117
    118
    119
    120
    121
    122
    123
    124
    125
    126
    127
    128
    129
    130
    131
    132
    133
    134
    135
    136
    137
    138
    139
    140
    141
    142
    143
    144
    145
    146
    147
    148
    149
    150
    151
    152
    153
    154
    155
    156
    157
    158
    159
    160
    161
    162
    163
    164
    165
    166
    167
    168
    169
    170
    171
    172
    173
    174
    175
    176
    177
    178
    179
    180
    181
    182
    183
    184
    185
    186
    187
    188
    189
    190
    191
    192
    193
    194
    195
    196
    197
    198
    199
    200
    201
    202
    203
    204
    205
    206
    207
    208
    209
    210
    211
    212
    213
    214
    215
    216
    217
    218
    219
    220
    221
    222
    223
    224
    225
    226
    227
    228
    229
    230
    231
    232
    233
    234
    235
    236
    237
    238
    239
    240
    241
    242
    243
    244
    245
    246
    247
    248
    249
    250
    251
    252
    253
    254
    255
    256
    257
    258
    259
    260
    261
    262
    263
    264
    265
    266
    267
    268
    269
    270
    271
    272
    273
    274
    275
    276
    277
    278
    279
    280
    281
    282
    283
    284
    285
    286
    287
    288
    289
    290
    291
    292
    293
    294
    295
    296
    297
    298
    299
    300
    301
    302
    303
    304
    305
    306
    307
    308
    309
    310
    311
    312
    313
    314
    315
    316
    317
    318
    319
    320
    321
    322
    323
    324
    325
    326
    327
    328
    329
    330
    331
    332
    333
    
    // DownloadOperation.m
    
    #import "DownloadOperation.h"
    
    @interface DownloadOperation (private)
    
    - (void)startElementLocalName:(const xmlChar*)localname
            prefix:(const xmlChar*)prefix
            URI:(const xmlChar*)URI
            nb_namespaces:(int)nb_namespaces
            namespaces:(const xmlChar**)namespaces
            nb_attributes:(int)nb_attributes
            nb_defaulted:(int)nb_defaulted
            attributes:(const xmlChar**)attributes;
    
    - (void)endElementLocalName:(const xmlChar*)localname
            prefix:(const xmlChar*)prefix URI:(const xmlChar*)URI;
    
    - (void)charactersFound:(const xmlChar*)ch
            len:(int)len;
    
    @end
    
    static void startElementHandler(
            void* ctx,
            const xmlChar* localname,
            const xmlChar* prefix,
            const xmlChar* URI,
            int nb_namespaces,
            const xmlChar** namespaces,
            int nb_attributes,
            int nb_defaulted,
            const xmlChar** attributes)
    {
        [(DownloadOperation*)ctx
                startElementLocalName:localname
                prefix:prefix URI:URI
                nb_namespaces:nb_namespaces
                namespaces:namespaces
                nb_attributes:nb_attributes
                nb_defaulted:nb_defaulted
                attributes:attributes];
    }
    
    static void endElementHandler(
            void* ctx,
            const xmlChar* localname,
            const xmlChar* prefix,
            const xmlChar* URI)
    {
        [(DownloadOperation*)ctx
                endElementLocalName:localname
                prefix:prefix
                URI:URI];
    }
    
    static void charactersFoundHandler(
            void* ctx,
            const xmlChar* ch,
            int len)
    {
        [(DownloadOperation*)ctx
                charactersFound:ch len:len];
    }
    
    static xmlSAXHandler _saxHandlerStruct = {
        NULL,            /* internalSubset */
        NULL,            /* isStandalone   */
        NULL,            /* hasInternalSubset */
        NULL,            /* hasExternalSubset */
        NULL,            /* resolveEntity */
        NULL,            /* getEntity */
        NULL,            /* entityDecl */
        NULL,            /* notationDecl */
        NULL,            /* attributeDecl */
        NULL,            /* elementDecl */
        NULL,            /* unparsedEntityDecl */
        NULL,            /* setDocumentLocator */
        NULL,            /* startDocument */
        NULL,            /* endDocument */
        NULL,            /* startElement*/
        NULL,            /* endElement */
        NULL,            /* reference */
        charactersFoundHandler, /* characters */
        NULL,            /* ignorableWhitespace */
        NULL,            /* processingInstruction */
        NULL,            /* comment */
        NULL,            /* warning */
        NULL,            /* error */
        NULL,            /* fatalError //: unused error() get all the errors */
        NULL,            /* getParameterEntity */
        NULL,            /* cdataBlock */
        NULL,            /* externalSubset */
        XML_SAX2_MAGIC,  /* initialized */
        NULL,            /* private */
        startElementHandler,    /* startElementNs */
        endElementHandler,      /* endElementNs */
        NULL,            /* serror */
    };
    
    @implementation DownloadOperation
    
    // Property
    @synthesize channel = _channel;
    
    //--------------------------------------------------------------//
    #pragma mark -- Initialize --
    //--------------------------------------------------------------//
    
    + (BOOL)automaticallyNotifiesObserversForKey:(NSString*)key
    {
        if ([key isEqualToString:@"isExecuting"] ||
            [key isEqualToString:@"isFinished"])
        {
            return YES;
        }
    
        return [super automaticallyNotifiesObserversForKey:key];
    }
    
    - (id)initWithRequest:(NSURLRequest*)request
    {
        if (![super init]) {
            return nil;
        }
    
        // 实例初始化
        _request = [request retain];
        _isExecuting = NO;
        _isFinished = NO;
        _channel = [[NSMutableDictionary dictionary] retain];
        [_channel setObject:[NSMutableArray array] forKey:@"items"];
        _currentItem = nil;
    
        return self;
    }
    
    - (void)dealloc
    {
        // 内存释放
        [_request release], _request = nil;
        [_connection cancel];
        [_connection release], _connection = nil;
        [_channel release], _channel = nil;
        [_currentCharacters release], _currentCharacters = nil;
    
        [super dealloc];
    }
    
    //--------------------------------------------------------------//
    #pragma mark -- Operating --
    //--------------------------------------------------------------//
    
    - (BOOL)isConcurrent
    {
        return YES;
    }
    
    - (BOOL)isExecuting
    {
        return _isExecuting;
    }
    
    - (BOOL)isFinished
    {
        return _isFinished;
    }
    
    - (void)start
    {
        // 开始下载
        if (![self isCancelled]) {
            // 创建XML解析器
            _parserContext = xmlCreatePushParserCtxt(&_saxHandlerStruct, self, NULL, 0, NULL);
    
            // 设定标志
            [self setValue:[NSNumber numberWithBool:YES] forKey:@"isExecuting"];
            _isChannel = NO;
            _isItem = NO;
    
            // 创建连接
            [NSURLConnection connectionWithRequest:_request delegate:self];
        }
    }
    
    - (void)cancel
    {
        // 释放XML解析器
        if (_parserContext) {
            xmlFreeParserCtxt(_parserContext), _parserContext = NULL;
        }
    
        [_connection cancel], _connection = nil;
        [self setValue:[NSNumber numberWithBool:NO] forKey:@"isExecuting"];
        [self setValue:[NSNumber numberWithBool:YES] forKey:@"isFinished"];
    
        [super cancel];
    }
    
    //--------------------------------------------------------------//
    #pragma mark -- NSURLConnection delegate --
    //--------------------------------------------------------------//
    
    - (void)connection:(NSURLConnection*)connection
            didReceiveData:(NSData*)data
    {
        // 添加解析数据
        xmlParseChunk(_parserContext, (const char*)[data bytes], [data length], 0);
    }
    
    - (void)connectionDidFinishLoading:(NSURLConnection*)connection
    {
        // 添加解析数据(结束)
        xmlParseChunk(_parserContext, NULL, 0, 1);
    
        // 释放XML解析器
        if (_parserContext) {
            xmlFreeParserCtxt(_parserContext), _parserContext = NULL;
        }
    
        // 设定标志
        _connection = nil;
        [self setValue:[NSNumber numberWithBool:NO] forKey:@"isExecuting"];
        [self setValue:[NSNumber numberWithBool:YES] forKey:@"isFinished"];
    }
    
    - (void)connection:(NSURLConnection*)connection
            didFailWithError:(NSError*)error
    {
        // 释放XML解析器
        if (_parserContext) {
            xmlFreeParserCtxt(_parserContext), _parserContext = NULL;
        }
    
        // 设定标志
        _connection = nil;
        [self setValue:[NSNumber numberWithBool:NO] forKey:@"isExecuting"];
        [self setValue:[NSNumber numberWithBool:YES] forKey:@"isFinished"];
    }
    
    //--------------------------------------------------------------//
    #pragma mark -- libxml handler --
    //--------------------------------------------------------------//
    
    - (void)startElementLocalName:(const xmlChar*)localname
            prefix:(const xmlChar*)prefix
            URI:(const xmlChar*)URI
            nb_namespaces:(int)nb_namespaces
            namespaces:(const xmlChar**)namespaces
            nb_attributes:(int)nb_attributes
            nb_defaulted:(int)nb_defaulted
            attributes:(const xmlChar**)attributes
    {
        // channel
        if (strncmp((char*)localname, "channel", sizeof("channel")) == 0) {
            _isChannel = YES;
    
            return;
        }
    
        // item
        if (strncmp((char*)localname, "item", sizeof("item")) == 0) {
            _isItem = YES;
    
            _currentItem = [NSMutableDictionary dictionary];
            [[_channel objectForKey:@"items"] addObject:_currentItem];
    
            return;
        }
    
        // title, link, description
        if (strncmp((char*)localname, "title", sizeof("title")) == 0 ||
            strncmp((char*)localname, "link", sizeof("link")) == 0 ||
            strncmp((char*)localname, "description", sizeof("description")) == 0)
        {
            // 创建字符串
            [_currentCharacters release], _currentCharacters = nil;
            _currentCharacters = [[NSMutableString string] retain];
        }
    }
    
    - (void)endElementLocalName:(const xmlChar*)localname
            prefix:(const xmlChar*)prefix URI:(const xmlChar*)URI
    {
        // channel
        if (strncmp((char*)localname, "channel", sizeof("channel")) == 0) {
            _isChannel = NO;
    
            return;
        }
    
        // item
        if (strncmp((char*)localname, "item", sizeof("item")) == 0) {
            _isItem = NO;
            _currentItem = nil;
    
            return;
        }
    
        // title, link, description
        if (strncmp((char*)localname, "title", sizeof("title")) == 0 ||
            strncmp((char*)localname, "link", sizeof("link")) == 0 ||
            strncmp((char*)localname, "description", sizeof("description")) == 0)
        {
            NSString*   key;
            key = [NSString stringWithCString:(char*)localname encoding:NSUTF8StringEncoding];
    
            NSMutableDictionary*    dict = nil;
            if (_isItem) {
                dict = _currentItem;
            }
            else if (_isChannel) {
                dict = _channel;
            }
    
            [dict setObject:_currentCharacters forKey:key];
            [_currentCharacters release], _currentCharacters = nil;
        }
    }
    
    - (void)charactersFound:(const xmlChar*)ch
            len:(int)len
    {
        // 添加解析到的字符串
        if (_currentCharacters) {
            NSString*   string;
            string = [[NSString alloc] initWithBytes:ch length:len encoding:NSUTF8StringEncoding];
            [_currentCharacters appendString:string];
            [string release];
        }
    }
    
    @end
    
    连接开始的时候(start函数)使用 xmlCreatePushParserCtxt 创建解析器实例,这里注意第二个参数,将DownloadOperation 的实例传到解析器内,这个正是回调函数中的第一个参数 — 作为回调函数的句柄调用类成员函数(当然,不使用实例方法,将回调函数设置成类方法也是可行的。但是当你使用到DownloadOperation中的成员等会有些不便,所以从OO的角度出发,还是传递回调函数的对象实例为佳)。
    开始下载的时候,因为数据是顺序得到的,所以一边下载,一边用 xmlParseChunk 传递给解析器。
    libxml的SAX句柄函数在xmlSAXHandler结构中定义。这个构造体内有30多个句柄定义,一般我们只需要登录其中几个就够了。比如例子中的 startElementNsSAX2Func、endElementNsSAX2Func、charactersSAXFunc 等,他们的定义如下:
    最后,因为用SAX解析,需要知道当前解析的位置,所以标记参数需要合理的使用。

    使用DOM解析

    上面我们已经介绍了,iPhone 中的XML解析器都是SAX的,如果仅仅对于比较小的XML文档,或者说想得到DOM树结构的XML文档来说,使用DOM解析还是有一定价值的(比如针对简单的SOAP,REST文档解析等)。

    Google Data APIs

    这里介绍一种使用第三方类库的方法,具体见这里。其实说是第三方类库,其实还是使用了libxml2,所以前期库文件和头文件的设置与上面libxml2是一致的。并将 -lxml2 加到link的设置中。
    使用的时候,先从这里下载并解冻 Google Data APIs Objective-C Client Library,然后将下面解开的文件拷贝到项目中去。
    1
    2
    3
    4
    
    GDataXMLNode.h
    GDataXMLNode.m
    GDataDefines.h
    GDataTargetNamespace.h
    
    解析的例子如下:
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    
    <users>
        <user id="0">
            <name>azalea</name>
            <email>azalea@azalea.net</email>
            <address country="Japan">Hokkaido</address>
        </user>
        <user id="1">
            <name>Baka.K.El.Doglla</name>
            <email>unknown@unknown.net</email>
            <address country="Doglla">Doglla</address>
        </user>
    </users>
    
    下面就是使用方法了,DOM的API使用起来还是感觉便利些:
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    23
    24
    25
    26
    
    #import "GDataXMLNode.h"
    
    - (void)applicationDidFinishLaunching:(UIApplication *)application {
    
        // load xml file as text
        NSString* path = [[NSBundle mainBundle] pathForResource:@"sample" ofType:@"xml"];
        NSString* fileText = [NSString stringWithContentsOfFile:path encoding:NSUTF8StringEncoding error:nil];
        NSLog(@"path:%d , fileText:%d",[path retainCount],[fileText retainCount]);
    
        // parse text as xml
        NSError* error;
        GDataXMLDocument* document = [[GDataXMLDocument alloc] initWithXMLString:fileText options:0 error:&error];
        GDataXMLElement *rootNode = [document rootElement];
    
        // get user names by xpath
        int count = 0;
        NSArray* userList = [rootNode nodesForXPath:@"//users/user/name" error:&error];
        for(GDataXMLNode* node in userList) {
            NSLog([node stringValue]);
        }
    
        // Configure and show the window
        [window addSubview:[navigationController view]];
        [window makeKeyAndVisible];
        [document release];
    }
    

    TouchXML

    TouchXML与上面的Google Data的XML解析器类似,也是基于libxml2的一款第三方DOM解析器。设置是一样的。
    下面开一个例子(从网上摘抄的):
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    23
    24
    25
    26
    27
    28
    29
    30
    31
    32
    33
    34
    35
    36
    37
    38
    39
    40
    41
    42
    43
    44
    45
    46
    47
    48
    49
    50
    51
    52
    53
    54
    55
    56
    57
    58
    59
    60
    61
    62
    63
    64
    65
    66
    67
    68
    69
    70
    71
    72
    73
    74
    75
    76
    77
    78
    79
    80
    81
    82
    83
    84
    85
    86
    87
    
    #pragma mark -
    #pragma mark NewCateBooksViewController
    //将xml字符串中的某些元素解析到一个数组中
    + (NSMutableArray*) parseBooks: (NSString*)xmlString /* NewCateBooksViewController */
    {
         if(0 == [xmlString length])
         return nil;
    
         NSMutableArray* items = [[[NSMutableArray alloc] init] autorelease];
         CXMLDocument *doc = [[CXMLDocument alloc] initWithXMLString: xmlString options: 0 error: nil];
         NSArray *resultNodes = nil;
         resultNodes = [doc nodesForXPath:@"//booklist" error:nil];//根结点
         if([resultNodes count])
         {
              CXMLElement *rootElement = [resultNodes lastObject];
              if(rootElement)
              {
                   NSArray* _bookElements = [rootElement elementsForName:@"book"];
                   for(CXMLElement* _bookElement in _bookElements)
                   {
                        RecomendBookListBean * bean = [[RecomendBookListBean alloc] init];
    
                        // if([_cateElements count])
                        // bean.b_cate_name = [[_cateElements lastObject] stringValue];
                        // bean.b_id = [_bookElement elementsForName:@"id"];
    
                        NSArray * idElements = [_bookElement elementsForName:@"id"];
    
                        if([idElements_ count])
                             bean.book_id=[[idElements_ lastObject]stringValue];
    
                        NSArray* nameElements = [_bookElement elementsForName:@"name"];
                        if([nameElements count])
                             bean.book_name = [[nameElements lastObject] stringValue];
    
                        NSArray* authorElements = [_bookElement elementsForName:@"author"];
                        if([authorElements count])
                             bean.book_author= [[authorElements lastObject] stringValue];
    
                        NSArray* urlElements = [_bookElement elementsForName:@"bookcoverurl"];
                        if([urlElements count])
                             bean.book_pic_url= [[urlElements lastObject] stringValue];
    
                        NSArray* descripElements = [_bookElement elementsForName:@"description"];
                        if([descripElements count])
                             bean.book_description = [[descripElements lastObject] stringValue];
    
                        NSArray* sizeElements = [_bookElement elementsForName:@"size"];
                        if([sizeElements count])
                                 bean.book_size = [[sizeElements lastObject] stringValue];
    
                        [items addObject: bean];
                        [bean release];
                   }
              }
          }
         [doc release];
         return items;
    }
    
    #pragma mark -
    
    -(void)updateArray:(NSString *)Url
    {
         NSError *error;
         NSURLResponse *response;
         NSData *dataReply;
         NSString *stringReply;
    
         NSMutableURLRequest *request =[NSMutableURLRequest requestWithURL:[NSURL URLWithString:Url]];
         [request setHTTPMethod:@"GET"];
         dataReply = [NSURLConnection sendSynchronousRequest:request returningResponse:&response error:&error];
    
         if(dataReply==nil&&error!=nil)
         {
              return;
         }
         else
         {
              stringReply = [[NSString alloc]initWithData:dataReply encoding:NSUTF8StringEncoding];
              [bookArray addObjectsFromArray:[xmlTry parseBooks:stringReply]]; //调用解析函数
              [stringReply release];//remember to release
    
         }
    
    }
    

    KissXML

    KissXML据说速度比 TouchXML 快些,暂时还没有试过,用兴趣的朋友可以试试。例子如下:
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    23
    24
    
    DDXMLDocument *doc = [[[DDXMLDocument alloc] initWithData:data options:0 error:&error] autorelease];
    
    DDXMLElement *root = [doc rootElement];
    [root addNamespace:[DDXMLNode namespaceWithName:@"idx" stringValue:@"urn:atom-extension:indexing"]];
    [root addNamespace:[DDXMLNode namespaceWithName:@"gr" stringValue:@"http://www.google.com/schemas/reader/atom/"]];
    [root addNamespace:[DDXMLNode namespaceWithName:@"media" stringValue:@"http://search.yahoo.com/mrss/"]];
    [root addNamespace:[DDXMLNode namespaceWithName:@"foo" stringValue:@"http://www.w3.org/2005/Atom"]];
    
    NSArray *titles = [root nodesForXPath:@"//foo:feed/foo:title" error:&error];
    NSArray *feedTitles = [root nodesForXPath:@"//foo:source/foo:title" error:&error];
    NSArray *feedIds = [root nodesForXPath:@"//foo:source/foo:id" error:&error];
    NSArray *entryTitles = [root nodesForXPath:@"//foo:entry/foo:title" error:&error];
    NSArray *contents = [root nodesForXPath:@"//foo:entry/foo:content" error:&error];
    NSArray *publisheds = [root nodesForXPath:@"//foo:entry/foo:published" error:&error];
    
    for (NSUInteger i = 0; i < [feedTitles count]; i++) {
    NSMutableDictionary *result = [[[NSMutableDictionary alloc] init] autorelease];
    [result setObject:[[feedIds objectAtIndex:i] stringValue] forKey:@"feed_id"];
    [result setObject:[[feedTitles objectAtIndex:i] stringValue] forKey:@"feed_title"];
    [result setObject:[[entryTitles objectAtIndex:i] stringValue] forKey:@"entry_title"];
    [result setObject:[[contents objectAtIndex:i] stringValue] forKey:@"content"];
    [result setObject:[[publisheds objectAtIndex:i] stringValue] forKey:@"published"];
        [self.objects addObject:result];
    }
    

    说到XML不得不提WEB应用中最常见的几种通讯规范:SOAP,XML-RPC,WSDL等,他们都是基于XML协定的。在下一节中我将介绍几种处理web应用的程序库。

    沒有留言:

    張貼留言