NSXMLParser
これは、いくつかの標準コードよりも少し注意が必要です。shipping
基本的に「必要な」を探しているときですが6.00
、これら2つのデータは異なるデリゲートメソッドで返されますが、これは正常なことです。ただし、通常、要素には「shipping
」という名前が付けられるためparser:didEndElement:namespaceURI:qualifiedName:
、メソッドに渡されたときに自動的に要素名が付けられます。
解決策は単純に見え、_currentAttributes
ivarがあり、次のparser:didStartElement:namespaceURI:qualifiedName:attributes:
ようなことをしてから、メソッド_currentAttributes = attributeDict;
でこれを処理します。didEndElement:
ただし、この適度に単純な場合でも、このスタイルは簡単に損益分岐点になりXML
ます。
これを処理する私の方法は、に渡された属性ディクショナリを格納しdidStartElement:
、要素名のキーのオブジェクトとしてディクショナリに設定することです。このスタイルを、ある種のcharacterBufferとしての標準的な使用法と組み合わせると、NSMutableString
すべてのロジックをメソッドに入れることができますdidEndElement:
。
補足:これがそうであるように、私は自分のNSXMLParserDelegate
クラスをNSXMLParser
サブクラスにすることもとても好きです。ただし、デリゲートメソッドは、そうでない場合は同じになります。
ItemParser.h
#import <Foundation/Foundation.h>
@interface ItemParser : NSXMLParser <NSXMLParserDelegate>
@property (readonly) NSDictionary *itemData;
@end
ItemParser.m
#import "ItemParser.h"
@implementation ItemParser {
NSMutableDictionary *_itemData;
NSMutableDictionary *_attributesByElement;
NSMutableString *_elementString;
}
-(NSDictionary *)itemData{
return [_itemData copy];
}
-(void)parserDidStartDocument:(NSXMLParser *)parser{
_itemData = [[NSMutableDictionary alloc] init];
_attributesByElement = [[NSMutableDictionary alloc] init];
_elementString = [[NSMutableString alloc] init];
}
-(void)parser:(NSXMLParser *)parser didStartElement:(NSString *)elementName namespaceURI:(NSString *)namespaceURI qualifiedName:(NSString *)qName attributes:(NSDictionary *)attributeDict{
// Save the attributes for later.
if (attributeDict) [_attributesByElement setObject:attributeDict forKey:elementName];
// Make sure the elementString is blank and ready to find characters
[_elementString setString:@""];
}
-(void)parser:(NSXMLParser *)parser foundCharacters:(NSString *)string{
// Save foundCharacters for later
[_elementString appendString:string];
}
-(void)parser:(NSXMLParser *)parser didEndElement:(NSString *)elementName namespaceURI:(NSString *)namespaceURI qualifiedName:(NSString *)qName{
if ([elementName isEqualToString:@"status"]){
// Element status only contains a string i.e. "OK"
// Simply set a copy of the element value string in the itemData dictionary
[_itemData setObject:[_elementString copy] forKey:elementName];
} else if ([elementName isEqualToString:@"pricing"]) {
// Pricing has an interesting attributes dictionary
// So copy the entries to the item data
NSDictionary *attributes = [_attributesByElement objectForKey:@"pricing"];
[_itemData addEntriesFromDictionary:attributes];
} else if ([elementName isEqualToString:@"price"]) {
// The element price occurs multiple times.
// The meaningful designation occurs in the "class" attribute.
NSString *class = [[_attributesByElement objectForKey:elementName] objectForKey:@"class"];
if (class) [_itemData setObject:[_elementString copy] forKey:class];
}
[_attributesByElement removeObjectForKey:elementName];
[_elementString setString:@""];
}
-(void)parserDidEndDocument:(NSXMLParser *)parser{
_attributesByElement = nil;
_elementString = nil;
}
-(void)parser:(NSXMLParser *)parser parseErrorOccurred:(NSError *)parseError{
NSLog(@"%@ with error %@",NSStringFromSelector(_cmd),parseError.localizedDescription);
}
-(BOOL)parse{
self.delegate = self;
return [super parse];
}
@end
そして、テストするために、XML
上記で投稿したものを「ItemXML.xml」という名前のファイルに保存しました。そして、このコードを使用してテストしました:
NSURL *url = [[NSBundle mainBundle] URLForResource:@"ItemXML" withExtension:@"xml"];
ItemParser *parser = [[ItemParser alloc] initWithContentsOfURL:url];
[parser parse];
NSLog(@"%@",parser.itemData);
私が得た結果は次のとおりです。
{
currency = USD;
items = "24.00";
shipping = "6.00";
status = OK;
symbol = "$";
tax = "1.57";
}