2009-05-08 32 views
5

Tôi đã tự làm quen với NSXMLParser từ SDK iPhone nhưng tôi thấy bản chất hướng sự kiện của nó khó xử cho mục đích của tôi. Tôi chỉ muốn trích xuất một số giá trị phần tử nhưng khái niệm này về việc phải xử lý startElement, foundCharacters và endElement có vẻ giống như nhiều công việc hơn là thực sự. Tôi chỉ cần nhìn vào điều này một cách sai lầm hoặc là có một cách đơn giản dựa trên cây/DOM làm việc với XML trong SDK iPhone?Cách tiếp cận tốt nhất để phân tích cú pháp XML trên iPhone

Nếu lời khuyên là chỉ làm việc với NSXMLParser, có các mẫu thiết kế nhất định mà tôi có thể sử dụng để giữ mã của tôi không có 5 mức ifed lồng nhau trong phương thức startElement không?

Trả lời

10

Nếu bạn đang sử dụng iPhone, sử dụng phân tích dựa trên cây có thể là bộ nhớ cấm. Tôi tin tưởng, tôi đã ở đó và tôi đã thử nhiều cách tiếp cận khác nhau trong năm tháng phát triển ứng dụng iPhone chính của mình. Phân tích cú pháp dựa trên cây hoạt động tốt cho đến khi bạn tải xuống luồng nhận xét của một người nào đó chứa 400 nhận xét rất dài, tốc độ trong khoảng 600KB dữ liệu thô. Khá xa so với kích thước của cây XML kết quả, bộ nhớ được cấp phát nội bộ trong khi tạo ra cây đó có thể rất lớn.

Tôi vết thương lên tạo ra một biến thể của NSXMLParser mà kéo dữ liệu từ một NSInputStream cung cấp hơn là sử dụng một đoạn duy nhất của dữ liệu, và đó chỉ có 1KB đi tại một thời điểm vào libxml để xử lý (NSXMLParser sử dụng libxml quá, nhưng chuyển 100% dữ liệu trong một lần).

Mã nguồn có sẵn on github (xem trong thư mục StreamingXMLParser). Bạn cũng sẽ tìm thấy một siêu lớp đại biểu trong đó; đối với hầu hết các nhu cầu phân tích cú pháp, bạn có thể phân lớp AQXMLParserDelegate và triển khai -start[Element]WithAttributes: (NSDictionary *) attrs-end[Element] trong lớp con của bạn. Những phương thức này sẽ được gọi cho bạn khi thẻ bắt đầu và thẻ kết thúc được phát hiện và bên trong thẻ kết thúc bạn có thể sử dụng self.characters để truy cập các ký tự nội dung hoặc CDATA của phần tử.

Để biết thêm về những dấu chân bộ nhớ tương đối của các phân tích cú pháp khác nhau (mặc dù trên Mac, không phải là iPhone) thấy gốc bài viết trên blog của tôi here và followup về NSXMLDocument here.

+0

Cảm ơn đây là thông tin hữu ích. Tôi đã kết thúc việc sử dụng startElement, foundCharacters, mô hình endElement và nó không quá tệ nhưng bây giờ tôi nhận thấy rằng NSXMLParser initWithContentsOfURL dường như tải toàn bộ tài liệu và để nó trong bộ nhớ trái với luồng nó - như bạn đã chỉ ra. Đó là kinda đáng ngạc nhiên vì không có lý do bạn cần truy cập vào toàn bộ tài liệu khi bạn đang sử dụng một cách tiếp cận phân tích dựa trên sự kiện. Tôi sẽ xem xét trong StreamingXMLParser. – Marplesoft

+0

Ok điều tra thêm. Bây giờ tôi nhận thấy rằng dấu chân bộ nhớ là moreso do tải xuống URL hơn là phân tích cú pháp thực tế. Tôi đang làm một tải xuống async nhưng nó dường như không phát hành các khối dữ liệu đã nhận được. – Marplesoft

+0

Vâng, các công cụ NSURLConnection phân bổ một bit công bằng của bộ nhớ trong khi làm việc của nó - và nếu bạn đang sử dụng SSL có ~ 1MB thêm phân bổ cho các đường ống mã hóa. Tôi vết thương bằng văn bản của riêng tôi wrapper xung quanh CFHTTPMessageRef và sử dụng để có được một dòng để nuôi phân tích cú pháp; đó là trong cùng một kho lưu trữ github, trong thư mục con HTTPMessage. –

1

Hãy xem đoạn mã sau, sử dụng libxml2, Matt Gallagher's libxml2 wrappersBen Copsey's ASIHTTPRequest để phân tích cú pháp tài liệu XML.

Ví dụ nodes loại NSArray* sẽ chứa NSDictionary* đối tượng mà bạn có thể phân tích đệ quy để nhận dữ liệu bạn muốn.

Hoặc, nếu bạn biết lược đồ của tài liệu XML của mình, bạn có thể viết truy vấn XPath để đưa bạn đến một giá trị nodeContent hoặc nodeAttribute trực tiếp.

ASIHTTPRequest *request = [ASIHTTPRequest alloc] initWithURL:[NSURL URLWithString:@"http://stackoverflow.com/"]; 
[request start]; 
NSError *error = [request error]; 
if (!error) { 
    NSData *response = [request responseData]; 
    NSLog(@"Root node: %@", [[self query:@"//" withResponse:response] description]); 
} 
else 
    @throw [NSException exceptionWithName:@"kHTTPRequestFailed" reason:@"Request failed!" userInfo:nil]; 
[request release]; 

... 

- (id) query:(NSString *)xpathQuery withResponse:(NSData *)respData { 
    NSArray *nodes = PerformXMLXPathQuery(respData, xpathQuery); 
    if (nodes != nil) 
     return nodes; 
    return nil; 
} 
0

Đặt lại mã từ XML địa chấn cung cấp API rất tốt tạo lớp con NSObject từ XML.

Nếu lời khuyên chỉ hoạt động với NSXMLParser, có một số mẫu thiết kế nào tôi có thể sử dụng để giữ mã của mình không có 5 mức lồng nhau trong phương thức startElement không?

Tôi phụ thuộc vào những gì bạn đang cố gắng làm.Bạn có thể đặt tên phần tử của bạn trong từ điển và thực hiện hành động dựa trên đối tượng có liên quan trong từ điển - đây chính là điều mà SeismicXML thực hiện.

Các vấn đề liên quan