2013-05-09 1 views
2

NSXMLparser에서 경로 표현식을 사용할 수 있습니까? 몇 가지 동일한 이름 태그가있는 XML 파일이 있지만 다른 요소에 있습니다. 이들을 구별 할 수있는 방법이 있습니까?NSXMLparser를 사용하면 같은 이름 태그를 가지고 있지만 다른 요소가있는 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

XML에 마지막 닫는 태그의'/'도 누락되었습니다. – Rob

답변

3

별도의 SchoolStudent 개체를 만들 것입니다. 파서는 currentSchoolcurrentStudent에 대한 속성을가집니다. 당신이 <name> 태그를 쳤을 때 당신의 파서가 <Student> 태그 안타 때마다, 파서가 </Student> 태그를 명중 할 때마다,

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*/ 
} 

미안 내 코드 조각이 너무 짧은이며, 지금이 입력 할 시간이별로 없습니다. 더 자세한 내용이 필요하면 나중에 코드를 추가 할 수 있습니다.


UPDATE

좀 더 세부 사항으로 이동하기위한 가장 빠른 방법은 내가 무엇을 찾고에 대한 코드를 보여주고, 코드로 모든 것을 설명하는 주석을 넣어 단지입니다. 이 부분에 대해 질문이 있거나 더 자세히 설명해야 할 사항이 있으면 무엇을 정교하게해야하는지 알려주고 최선을 다할 것입니다.

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"); 
    } 
} 
+0

제발, 자세한 내용은, 내가 어떻게 하나의 NSDictionnary에있는 모든 요소를 ​​추가 할 수 있는지 이해하지 못했기 때문에. –

+0

@ user2299789 : NSDictionaries를 서로 중첩시킬 수 있으므로 필요한 모든 것이 들어있는 마지막 NSDictionary로 끝낼 수 있습니다. 파서의 .m 파일에있는 코드로 질문을 업데이트 할 수 있습니까? 파서 위임 메서드를 어떻게 사용하고 있는지보고 싶습니다. – GeneralMike

+0

예, 제 질문이지만, 지금까지는 파서를 작성하지 않았습니다. 왜냐하면 나는 해결책을 찾지 못했기 때문이다. –

1

1) 파서가 학교 태그를 발견 할 때, 배열을 초기화이 배열은 생성 할 모든 학생 오브젝트를 개최합니다 다음은 XML이다.

2) 학생 시작 태그가 나타날 때마다 학생 개체를 만듭니다.

3) 다음 파서 [studentObj setId는 : parsedContent]로 파싱 ID 태그 발생

4) 다음 파서 이름표가 발생 [studentObj에서는 setName는 : parsedContent]

5) 지금 파서 학생 태그의 단부를 발견 이제이 studentObj를 1 단계에서 초기화 한 배열에 추가하십시오.

1

한 가지 방법은 두 BOOL 급 호텔/인스턴스 변수를 가지고하는 것입니다 하나는 학교를위한 것이고 다른 하나는 학생들을위한 것입니다. 그런 다음 didStartElement에서 elementName@"School" 또는 @"Student" 인 경우 적절한 부울 속성/ivar를 설정합니다. 마찬가지로 didEndElement에서 elementName@"School" 또는 @"Student" 인 경우 적절한 부울 속성/ivar를 지 웁니다. 그런 다음 @"Name"을 구문 분석 할 때 두 개의 부울 속성/ivars를 검사하여 구문 분석하려는 구문을 확인하고 적절한 단계를 수행 할 수 있습니다. 예를 들어, 학생 부울 값이 참이면 학생 이름이 분명합니다. 학생 부울이 거짓이지만 학교 부울 값이 참이면 학교의 이름입니다.

문제를 해결하는 우아한 방법 (예 : 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 피드에 대해 매우 구체적인 구문 분석기를 작성하는 경우에는 관련성이없는 것처럼 보일 수 있지만 실제로는 더 논리적 인 구조라는 것을 알고 있습니다.

+0

예,이 방법으로 모든 elemebt를 하나의 NSDictionnary에 추가 할 수 있습니까? –

+0

이 설정을 사용하면 실제로 학생용으로'BOOL' 만 필요합니다. 맞습니까? 이름이 학생의 이름이 아니라면 가정은 학교의 이름이어야합니다. – GeneralMike

+0

@GeneralMike - 물론이 XML에 대해 하나의 부울 만 필요합니다. (사실, 당신이 파싱하고 트리의 노드를 채우는 구조를 가질 때, 당신은 어떤 것도 필요로하지 않습니다.) 나는 그것을 아주 명백하고 초 간단하게 만들려고 노력했습니다. 두 개의 부울을 사용하면 좀 더 강력 해져 형식이 잘못된 XML을 발견 할 수 있습니다. 나중에 '학교'태그가 자체 이름이있는 '구역'구조에 포함 된 경우 처리 할 수 ​​있습니다 (예 : 사람들이 종종 단순한 변환 그들의 XML 중) 등등. – Rob