Ios 使用NSXMLparser,如何解析具有相同名称标记但元素不同的xml文件?

Ios 使用NSXMLparser,如何解析具有相同名称标记但元素不同的xml文件?,ios,xml,nsxmlparser,Ios,Xml,Nsxmlparser,可以在NSXMLparser中给出路径表达式吗?我有一个XML文件,它有几个相同的名称标记,但它们位于不同的元素中。有没有办法区分它们。以下是XML: <Schools> <School> <ID>335823</ID> <Name>Fairfax High School</Name> <Student>

可以在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>

335823
费尔法克斯高中
4195653
威尔·特纳
4195654
布鲁斯·帕特洛
4195655
桑托什·戈斯瓦米
1)初始化数组当解析器遇到School标记时,该数组将保存您要创建的所有学生对象

2) 每次看到学生开始标记时创建学生对象

3) 然后解析器遇到ID标记,将其解析为[studentObj setId:parsedContent]

4) 然后解析器遇到Name标记[studentObj setName:parsedContent]


5) 现在解析器遇到了student标记的末尾,现在将这个studentObj添加到您在步骤1中初始化的数组中,我将创建单独的
School
student
对象。您的解析器将具有
currentSchool
currentStudent
的属性。每当解析器点击
标记时,调用

self.currentStudent = [[MyStudentObject alloc] init];
每当解析器点击
标记时,调用

self.currentStudent = nil;
然后,当您点击
标记时,您可以检查是否有
currentStudent
。如果你知道,那么这个名字就是那个学生的名字。如果没有当前学生,则名称为学校名称

if (self.currentStudent)
{
    self.currentStudent.name = /*string between <name> tags*/
}
else
{
    self.currentSchool.name = /*string between <name> tags*/
}
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
学校教师

#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

一种方法是只设置两个
BOOL
class property/ivar,一个用于学校,一个用于学生。然后在
didStartElement
中,如果
元素名
@“学校”
@“学生”
,则设置相应的布尔属性/ivar。同样,在
didEndElement
中,如果
elementName
@“School”
@“Student”
,则清除相应的布尔属性/ivar。然后,在解析
@“Name”
时,您可以检查这两个布尔属性/ivar,查看您正在解析的是哪一个,并采取相应的步骤。(例如,如果学生布尔值为true,则名称显然是学生。如果学生布尔值为false,但学校布尔值为true,则名称是学校的名称。)

有更优雅的解决问题的方法(例如),但这可能是最简单的


顺便说一句,我不知道您是否对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>

您可以编写一个解析器来处理前者,但是当您进入一个更动态生成结果的世界时,让XML更准确地反映底层数据的结构是很有用的。我知道,当您为这个XML提要编写一个非常特定的解析器时,它可能看起来不相关,但实际上它是一个更符合逻辑的结构。

请提供更多详细信息,因为我不明白如何在一个NSDictionary中添加所有元素。@user2299789:您可以将NSDictionary嵌套在另一个NSDictionary中,所以,如果你需要的话,你可以最终得到一本包含所有内容的词典。您能用解析器的.m文件中的代码更新您的问题吗?我想看看您是如何使用解析器委托方法的。是的,这是我的问题,但直到现在我还没有编写解析器的。文件,因为我没有找到解决方案。是的,使用此方法,我可以在一个目录中添加所有元素?使用此设置,学生只需要1
BOOL
,对吗?假设名称不是学生的名称,则必须是学校的名称。@GeneralMike-显然,是的,此XML只需要一个布尔值。(事实上,当你有了解析和填充树节点的结构时,你不需要任何东西。)我只是想让它变得非常明显和简单。通过使用两个布尔值,您将更加健壮,能够检测格式错误的XML,能够处理
Schools
标记是否随后嵌入到具有自己名称的
Districts
结构中(例如,人们经常给我们他们的XML的简化格式),等等@user2299789-是的,您可以。顺便说一句,我已经更新了我的答案,提出了一个关于改进XML结构的建议。现在这可能没什么大不了的,但它更符合逻辑(如果你编写了一个动态解析结果的解析器,你会感谢你自己这么做)。@user2299789我上传了一个示例项目,它绕过了你对
BOOL
的困惑,并演示了一个可以将XML解析为树结构的解析器,这完全消除了“如何确保将
Name
元素附加到正确元素(学生的学校版本)”:这可能太多,您无法接受,但它将任意深度嵌套标签的XML提要解析为一个结构,然后您可以导航。您的示例XML(或至少是我的格式副本)在文档中有所体现。您的XML也缺少最后结束标记上的
/
#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
#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
#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
- (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");
    }
}
<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>
    <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>