の解析に関しては、がの場合に辞書からcategory
取得されます。didStartElement
attributes
elementName
@"Product"
「最善のアプローチ」に関しては、データ構造を決定するだけです。カテゴリディクショナリエントリの配列であるNSMutableArrayを作成することをお勧めします。これは、カテゴリごとに1つであり、ディクショナリ内のオブジェクトの1つは、そのカテゴリ内の製品の配列になります。
その構造ができたら、3番目の質問に答えることはおそらく明白です。
まず、XMLには次のような外部タグが本当に必要です。
<Products>
<Product category="ABC">
<Item_number>123</Item_number>
<Description>Coffee table</Description>
</Product>
<Product category="ABC">
<Item_number>456</Item_number>
<Description>Lamp shade</Description>
</Product>
<Product category="XYZ">
<Item_number>789</Item_number>
<Description>Orange chair</Description>
</Product>
</Products>
次に、カテゴリの配列が必要であり、カテゴリごとに製品の配列が必要であると仮定すると、実装は次のようになります。まず、いくつかのプロパティが必要です。1つは最終結果用で、もう2つは解析中に使用される一時変数用です。
// this is our final result, an array of dictionaries for each categor
@property (nonatomic, strong) NSMutableArray *categories;
// these are just temporary variables used during the parsing
@property (nonatomic, strong) NSMutableString *parserElementValue;
@property (nonatomic, strong) NSMutableDictionary *parserProduct;
そして、NSXMLParserDelegate
メソッドは次のようになります。
#pragma mark - NSXMLParser delegate methods
- (void)parserDidStartDocument:(NSXMLParser *)parser
{
self.categories = [NSMutableArray array];
}
- (void)parser:(NSXMLParser *)parser didStartElement:(NSString *)elementName namespaceURI:(NSString *)namespaceURI qualifiedName:(NSString *)qName attributes:(NSDictionary *)attributeDict
{
NSArray *subElementNames = @[@"Item_number", @"Description"];
if ([elementName isEqualToString:@"Product"])
{
// get the name of the category attribute
NSString *categoryName = [attributeDict objectForKey:@"category"];
NSAssert(categoryName, @"no category found");
// search our array of dictionaries of cateogries to see if we have one with a name equal to categoryName
__block NSMutableDictionary *parserCurrentCategory = nil;
[self.categories enumerateObjectsUsingBlock:^(id obj, NSUInteger idx, BOOL *stop) {
if ([categoryName isEqualToString:[obj objectForKey:@"name"]])
{
parserCurrentCategory = obj;
*stop = YES;
}
}];
// if we didn't find one, let's create one and add it to our array of cateogires
if (!parserCurrentCategory)
{
parserCurrentCategory = [NSMutableDictionary dictionaryWithObjectsAndKeys:
categoryName, @"name",
[NSMutableArray array], @"items",
nil];
[self.categories addObject:parserCurrentCategory];
}
// Now let's add an entry to the items array for the product being added
self.parserProduct = [NSMutableDictionary dictionary];
[[parserCurrentCategory objectForKey:@"items"] addObject:self.parserProduct];
}
else if ([subElementNames containsObject:elementName])
{
self.parserElementValue = [NSMutableString string];
[self.parserProduct setObject:self.parserElementValue forKey:elementName];
}
}
- (void)parser:(NSXMLParser *)parser foundCharacters:(NSString *)string
{
if (self.parserElementValue)
[self.parserElementValue appendString:string];
}
- (void)parser:(NSXMLParser *)parser didEndElement:(NSString *)elementName namespaceURI:(NSString *)namespaceURI qualifiedName:(NSString *)qName
{
if ([elementName isEqualToString:@"Product"])
{
self.parserProduct = nil;
}
else if (self.parserElementValue)
{
self.parserElementValue = nil;
}
}
- (void)parserDidEndDocument:(NSXMLParser *)parser
{
// all done, do whatever you want, just as reloadData for your table
NSLog(@"%s categories = %@", __FUNCTION__, self.categories);
}
- (void)parser:(NSXMLParser *)parser parseErrorOccurred:(NSError *)parseError
{
NSLog(@"%s error=%@", __FUNCTION__, parseError);
}