LoginSignup
0
0

More than 5 years have passed since last update.

AFNetworkingでAPIにアクセスしてXMLデータをパースする

Last updated at Posted at 2016-09-15

完成予想図

スクリーンショット 2016-09-15 午後11.41.29.png

THE雑ですがGitHubに今回作成したソースをプッシュしておきました

作業環境

  • OSX 10.11.6
  • Xcode7.3.1
  • Objective-C
  • CocoaPods 0.39.0
    • AFNetworking 3.1.0

準備

スクリーンショット 2016-09-15 午後9.53.03.png

ここまで準備をしてから始めます。

面倒なのでMVCで実装します。

使用するデータ

サンプル XML ファイル (books.xml) | MicroSoft

上記データを使わせていただきます!!
また、データは私のサーバにアップロードしているので使いたい方は使ってください!

catalog
→book
→→author
→→title
→→genre
→→price
→→publish_date
→→description

上記のようなデータ構造になっているのでTableViewにデータを表示させてみようと思います!
(矢印が入れ子)

実装

XML整形ライブラリ

使用するライブラリ?
https://github.com/nnsnodnb/XML-to-NSDictionary
本家

自分なりにARCに対応させました。開発がすでに止まっているのでPRを出してもマージされることはないでしょう!

vender フォルダに XmlReader.h 及び XmlReader.m を突っ込んでおく!

Model Object

スクリーンショット 2016-09-15 午後10.12.25.png

Bookクラスを作っておく。中身は以下

Book.h
#import <Foundation/Foundation.h>

@interface Book : NSObject

@property (nonatomic) NSString *author;
@property (nonatomic) NSString *title;
@property (nonatomic) NSString *genre;
@property (nonatomic) NSString *price;
@property (nonatomic) NSString *publishDate;
@property (nonatomic) NSString *bookDescription;

@end

description に関しては予約語なので bookDescription とした

TableViewCell クラス

TableViewCell.h
#import <UIKit/UIKit.h>
#import "Book.h"

@interface TableViewCell : UITableViewCell

@property (weak, nonatomic) IBOutlet UILabel *authorLabel;
@property (weak, nonatomic) IBOutlet UILabel *titleLabel;
@property (weak, nonatomic) IBOutlet UILabel *genreLabel;
@property (weak, nonatomic) IBOutlet UILabel *priceLabel;
@property (weak, nonatomic) IBOutlet UILabel *publicDateLabel;
@property (weak, nonatomic) IBOutlet UILabel *descriptionLabel;

- (void)setConfigure:(Book *)model;

@end
TableViewCell.m

#import "TableViewCell.h"

@implementation TableViewCell

- (void)awakeFromNib {
    [super awakeFromNib];
}

- (void)setSelected:(BOOL)selected animated:(BOOL)animated {
    [super setSelected:selected animated:animated];
}

- (void)setConfigure:(Book *)model {
    self.authorLabel.text = [model.author stringByTrimmingCharactersInSet:[NSCharacterSet whitespaceAndNewlineCharacterSet]];
    self.titleLabel.text = [model.title stringByTrimmingCharactersInSet:[NSCharacterSet whitespaceAndNewlineCharacterSet]];
    self.genreLabel.text = [model.genre stringByTrimmingCharactersInSet:[NSCharacterSet whitespaceAndNewlineCharacterSet]];
    self.priceLabel.text = [model.price stringByTrimmingCharactersInSet:[NSCharacterSet whitespaceAndNewlineCharacterSet]];
    self.publicDateLabel.text = [model.publishDate stringByTrimmingCharactersInSet:[NSCharacterSet whitespaceAndNewlineCharacterSet]];
    self.descriptionLabel.text = [model.bookDescription stringByTrimmingCharactersInSet:[NSCharacterSet whitespaceAndNewlineCharacterSet]];
}

@end

改行が含まれていたので改行を削除する処理をしています。

スクリーンショット 2016-09-15 午後10.17.09.png

当たり前なところは端折りながらやります!

スクリーンショット 2016-09-15 午後10.21.23.png

デザイン性に欠けていますがとりあえずこんな感じでstoryboardを編集

DescriptionはLineを0に設定しています。

XML整形ライブラリの補足

なんかkeyの中に更にkeyが入っているという謎仕様ww

AFNetworking当たりのお仕事

GetXmlData.h
#import <Foundation/Foundation.h>
#import "Book.h"

@protocol CallBackDelegate <NSObject>

- (void)callbackWithError;

@end

typedef void (^Callback)(NSArray<Book *>* dataSource);

@interface GetXmlData : NSObject

@property (weak, nonatomic) id<CallBackDelegate> delegate;
- (void)requestXmlDataWithCallback:(Callback)callback;

@end
GetXmlData.m
#import "GetXmlData.h"
#import "XMLReader.h"
#import <AFNetworking/AFNetworking.h>

static NSString *const accessUrl = @"https://dl.nnsnodnb.moe/ios-app/sample.xml";

@implementation GetXmlData

- (void)requestXmlDataWithCallback:(Callback)callback {
    AFHTTPSessionManager *manager = [AFHTTPSessionManager manager];
    AFHTTPRequestSerializer * requestSerializer = [AFHTTPRequestSerializer serializer];
    AFHTTPResponseSerializer * responseSerializer = [AFHTTPResponseSerializer serializer];
    responseSerializer.acceptableContentTypes = [NSSet setWithObjects:@"text/xml", nil];
    manager.responseSerializer = responseSerializer;
    manager.requestSerializer = requestSerializer;

    NSMutableArray<Book *> *dataSource = [NSMutableArray array];
    __weak typeof (self) wself = self;

    [manager GET:accessUrl
      parameters:nil
        progress:nil
         success:^(NSURLSessionDataTask * _Nonnull task, id  _Nullable responseObject) {
             NSData *data = (NSData *)responseObject;
             NSDictionary<NSString *, NSDictionary *> *dictionary = [XMLReader dictionaryForXMLData:data
                                                                                              error:nil];
             NSDictionary<NSString *, NSDictionary *> *category = dictionary[@"catalog"];
             for (NSDictionary<NSString *, NSDictionary *> *book in category[@"book"]) {
                 Book *model = [Book new];
                 model.author = book[@"author"][@"text"];
                 model.title = book[@"title"][@"text"];
                 model.genre = book[@"genre"][@"text"];
                 model.price = book[@"price"][@"text"];
                 model.publishDate = book[@"publish_date"][@"text"];
                 model.bookDescription = book[@"description"][@"text"];

                 [dataSource addObject:model];
             }
             callback(dataSource);
         } failure:^(NSURLSessionDataTask * _Nullable task, NSError * _Nonnull error) {
             if ([wself.delegate respondsToSelector:@selector(callbackWithError)]) {
                 [wself.delegate callbackWithError];
             }
         }];
}

@end

+ (NSDictionary *)dictionaryForXMLData:(NSData *)data error:(NSError *)error;
上記のようなクラスメソッドが用意されているので responseObject をNSDataに変換してあげて、このメソッドに当ててあげるとグチャグチャなNSDictionaryが返ってきます!!
こんなものか。

ViewControllerは?

ViewController.m
#import "Book.h"
#import "GetXmlData.h"
#import "TableViewCell.h"
#import "ViewController.h"

@interface ViewController () <UITableViewDataSource, UITableViewDelegate, CallBackDelegate>

@property (weak, nonatomic) IBOutlet UITableView *tableView;
@property (nonatomic) NSArray<Book *> *dataSource;
@property (nonatomic) GetXmlData *getXmlData;

@end

@implementation ViewController

- (void)viewDidLoad {
    [super viewDidLoad];
    self.dataSource = [NSArray array];
    self.tableView.dataSource = self;
    self.tableView.delegate = self;

    self.getXmlData = [GetXmlData new];
    self.getXmlData.delegate = self;

    __weak typeof (self) wself = self;
    [self.getXmlData requestXmlDataWithCallback:^(NSArray<Book *> *dataSource) {
        wself.dataSource = dataSource;
        [wself.tableView reloadData];
    }];
}

- (void)didReceiveMemoryWarning {
    [super didReceiveMemoryWarning];
}

#pragma mark - UITableViewDataSource

- (NSInteger)tableView:(UITableView *)tableView numberOfRowsInSection:(NSInteger)section {
    return self.dataSource.count;
}

- (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath {
    TableViewCell *cell = [tableView dequeueReusableCellWithIdentifier:@"Cell"
                                                          forIndexPath:indexPath];
    [cell setConfigure:self.dataSource[indexPath.row]];

    return cell;
}


#pragma mark - UITableViewDelegate

- (void)tableView:(UITableView *)tableView didSelectRowAtIndexPath:(NSIndexPath *)indexPath {
    [tableView deselectRowAtIndexPath:indexPath animated:YES];
}

#pragma mark - CallBackDelegate

- (void)callbackWithError {
    NSLog(@"Error");
}

@end

最後に

なんか最後はぶっ飛ばしで行きましたが、なんとかなったのではないでしょうか?
今回使用したデータが悪かったのかなんかちょっと時間をかけすぎてしまいました。

0
0
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
0
0