是否可以在NSXMLparser中提供路径表达式?我有一个XML文件,它有几个相同的名称标签,但它们在不同的元素中。有没有办法区分它们。这是XML:
<Schools>
<School>
<ID>335823</ID>
<Name>Fairfax High School</Name>
<Student>
<ID>4195653</ID>
<Name>Will Turner</Name>
</Student>
<Student>
<ID>4195654</ID>
<Name>Bruce Paltrow</Name>
</Student>
<Student>
<ID>4195655</ID>
<Name>Santosh Gowswami</Name>
</Student>
</School>
<Schools>
答案 0 :(得分:3)
我会创建单独的School
和Student
个对象。您的解析器将具有currentSchool
和currentStudent
的属性。每当您的解析器点击<Student>
标记时,请调用
self.currentStudent = [[MyStudentObject alloc] init];
每当您的解析器点击</Student>
标记时,请调用
self.currentStudent = nil;
然后,当您点击<name>
标记时,您可以查看是否有currentStudent
。如果您这样做,那么名称就是该学生的名字。如果没有现在的学生,则该名称是学校的名称。
if (self.currentStudent)
{
self.currentStudent.name = /*string between <name> tags*/
}
else
{
self.currentSchool.name = /*string between <name> tags*/
}
抱歉,我的代码片段非常简短,我现在没有太多时间输入。如果需要更多细节,我可以稍后添加更多代码。
更新
让我了解更多细节的最快方式就是展示我正在寻找的代码,并将解释所有内容的注释放入代码中。如果对此任何部分有任何疑问,或者需要进一步解释,请告诉我要详细说明的内容,我会尽力而为。
StudentXML.h
#import <Foundation/Foundation.h>
@interface StudentXML : NSObject
@property (nonatomic, strong) NSString *ID; // MAKE SURE THIS EXACTLY MATCHES THE ELEMENT IN THE XML!!
@property (nonatomic, strong) NSString *Name; // MAKE SURE THIS EXACTLY MATCHES THE ELEMENT IN THE XML!!
@end
StudentXML.m
#import "StudentXML.h"
@implementation StudentXML
@end
SchoolXML.h
#import <Foundation/Foundation.h>
#import "StudentXML.h"
@interface SchoolXML : NSObject
@property (nonatomic, strong) NSString *ID; // MAKE SURE THIS EXACTLY MATCHES THE ELEMENT IN THE XML!!
@property (nonatomic, strong) NSString *Name; // MAKE SURE THIS EXACTLY MATCHES THE ELEMENT IN THE XML!!
@property (nonatomic, strong) NSMutableArray *studentsArray; // Array of StudentXML objects
@end
SchoolXML.m
#import "SchoolXML.h"
@implementation SchoolXML
// Need to overwrite init method so that array is created when new SchoolXML object is created
- (SchoolXML *) init;
{
if (self = [super init])
{
self.studentsArray = [[NSMutableArray alloc] init];
return self;
}
else
{
NSLog(@"Error - SchoolXML object could not be initialized in init on SchoolXML.m");
return nil;
}
}
@end
SchoolsParser.h
#import <Foundation/Foundation.h>
#import "SchoolXML.h"
#import "StudentXML.h"
@interface SchoolsParser : NSObject
{
NSMutableString *currentElementValue; // Will hold the string between tags until we decide where to put it
}
@property (nonatomic, strong) SchoolXML *currentSchool; // Will hold the school that is in the process of being filled
@property (nonatomic, strong) StudentXML *currentStudent; // Will hold the student that is in the process of being filled
@property (nonatomic, strong) NSMutableArray *allSchools; // This is the final list of all the data in the XML file
- (void)parser:(NSXMLParser *)parser didStartElement:(NSString *)elementName namespaceURI:(NSString *)namespaceURI qualifiedName:(NSString *)qualifiedName attributes:(NSDictionary *)attributeDict;
- (void)parser:(NSXMLParser *)parser foundCharacters:(NSString *)string;
- (void)parser:(NSXMLParser *)parser didEndElement:(NSString *)elementName namespaceURI:(NSString *)namespaceURI qualifiedName:(NSString *)qName;
@end
SchoolsParser.m
#import "SchoolsParser.h"
@implementation SchoolsParser
- (void)parser:(NSXMLParser *)parser didStartElement:(NSString *)elementName namespaceURI:(NSString *)namespaceURI qualifiedName:(NSString *)qualifiedName attributes:(NSDictionary *)attributeDict
// This method will be hit each time the parser sees an opening tag
// elementName is the string between the <> (example "School")
{
if ([elementName isEqualToString:@"School"])
{
self.currentSchool = [[SchoolXML alloc] init];
}
else if ([elementName isEqualToString:@"Student"])
{
self.currentStudent = [[StudentXML alloc] init];
}
}
- (void)parser:(NSXMLParser *)parser foundCharacters:(NSString *)string
// This method will be hit each time the parser sees a string between tags
// string is the value between the open and close tag (example "Fairfax High School")
// We take string and hold onto it until we can decide where it should be put
{
currentElementValue = [[NSMutableString alloc] initWithString:string];
}
- (void)parser:(NSXMLParser *)parser didEndElement:(NSString *)elementName namespaceURI:(NSString *)namespaceURI qualifiedName:(NSString *)qName
// This method will be hit each time the parser sees an closing tag
// elementName is the string between the </> (example "School")
// This is the method where we decide where we want to put the currentElementValue string
{
if ([elementName isEqualToString:@"Student"])
{
// Put the current student into the studentsArray of the currentSchool
[self.currentSchool.studentsArray addObject:self.currentStudent];
// We've finished building this student and have put it into the school we wanted, so we clear out currentStudent so we can reuse it next time
self.currentStudent = nil;
}
else if ([elementName isEqualToString:@"School"])
{
// Put the current school into the allSchoolsArray to send back to our view controller
[self.allSchools addObject:self.currentSchool];
// We've finished building this school and have put it into the return array, so we clear out currentSchool so we can reuse it next time
self.currentSchool = nil;
}
else if ([elementName isEqualToString:@"Schools"])
{
// We reached the end of the XML document
return;
}
else
// This is either a Name or an ID, so we want to put it into the correct currentSomething we are building
{
if (self.currentStudent)
// There is a currentStudent, so the Name or ID we found is that of a student
{
// Since the properties of our currentStudent object exactly match the elementNames in our XML, the parser can automatically fills values in where they need to be without us doing any more
// For example, it will take "Will Turner" in the <Name> tags in the XML and put it into the .Name property of our student
[self.currentStudent setValue:currentElementValue forKey:elementName];
}
else
// There was no student, so the Name or ID we found is that of a school
{
// Since the properties of our currentStudent object exactly match the elementNames in our XML, the parser can automatically fills values in where they need to be without us doing any more
// For example, it will take "Fairfax High School" in the <Name> tags in the XML and put it into the .Name property of our school
[self.currentSchool setValue:currentElementValue forKey:elementName];
}
}
// We've now put the string in currentElementValue where we wanted it, so we clear out currentElementValue so we can reuse it next time
currentElementValue = nil;
}
-(void)parser:(NSXMLParser *)parser parseErrorOccurred:(NSError *)parseError
{
NSLog(@"Error in SchoolsParser.m");
NSLog(@"%@",parseError.description);
}
@end
UIViewController.m,你想要开始解析(确保你#include
SchoolXML,StudentXML和SchoolsParser):
- (void) startSchoolParser
{
NSXMLParser *nsXmlParser = [[NSXMLParser alloc] initWithData:responseData]; // where "responseData" is the NSData object that holds your XML
SchoolsParser *parser = [[SchoolsParser alloc] init];
[nsXmlParser setDelegate:parser];
if ([nsXmlParser parse])
{
// Parsing was successful
NSArray *allSchools = parser.allSchools;
// You can now loop through allSchools and use the data how ever you want
// For example, this code just NSLog's all the data
for (SchoolXML *school in allSchools)
{
NSLog(@"School Name = %@",school.Name);
NSLog(@"School ID = %@",school.ID);
for (StudentXML *student in school.studentsArray)
{
NSLog(@"Student Name = %@",student.Name);
NSLog(@"Student ID = %@",student.ID);
}
}
}
else
{
NSLog(@"Parsing Failed");
}
}
答案 1 :(得分:1)
1)当解析器遇到School标签时初始化一个数组,该数组将保存您要创建的所有Student对象。
2)每次看到学生开始标记时创建学生对象。
3)然后解析器遇到ID标签将其解析为[studentObj setId:parsedContent]
4)然后解析器遇到Name标签[studentObj setName:parsedContent]
5)现在解析器遇到学生结束标记,现在将此studentObj添加到您在步骤1中初始化的数组
答案 2 :(得分:1)
一种方法是只有两个BOOL
类属性/ ivars,一个用于学校,一个用于学生。然后在didStartElement
中,如果elementName
是@"School"
或@"Student"
,则设置相应的布尔属性/ ivar。同样,在didEndElement
中,如果elementName
为@"School"
或@"Student"
,则清除相应的布尔属性/ ivar。然后,在解析@"Name"
时,您可以检查这两个布尔属性/ ivars以查看您正在解析的那个并采取适当的步骤。 (例如,如果学生布尔值为true,那么显然名称是学生。如果学生布尔值为假,但学校布尔值为真,则该名称为学校名称。)
有更优雅的方法来解决问题(例如XML Node Parser),但这可能是最简单的。
顺便说一句,我不知道你是否对XML的结构有任何发言权,但我认为最好将所有数组都包装在自己的元素中。因此,而不是:
<Schools>
<School>
<ID>335823</ID>
<Name>Fairfax High School</Name>
<Student>
<ID>4195653</ID>
<Name>Will Turner</Name>
</Student>
<Student>
<ID>4195654</ID>
<Name>Bruce Paltrow</Name>
</Student>
<Student>
<ID>4195655</ID>
<Name>Santosh Gowswami</Name>
</Student>
</School>
<Schools>
我希望看到包含学生列表的“学生”元素名称。您的最终结束Schools
代码也缺少/
。
<Schools>
<School>
<ID>335823</ID>
<Name>Fairfax High School</Name>
<Students>
<Student>
<ID>4195653</ID>
<Name>Will Turner</Name>
</Student>
<Student>
<ID>4195654</ID>
<Name>Bruce Paltrow</Name>
</Student>
<Student>
<ID>4195655</ID>
<Name>Santosh Gowswami</Name>
</Student>
</Students>
</School>
</Schools>
您可以编写一个处理前者的解析器,但是当您进入一个更动态生成结果的世界时,让XML更准确地反映基础数据的结构是有用的。我知道,当你为这个XML feed编写一个非常具体的解析器时,它可能看起来无关紧要,但它确实是一个更合理的结构。