[iOS] XML Parsing Basics

此份文件為個人學習事件驅動XML程式的翻譯,內文請參考蘋果官方文件,若有翻譯錯誤請見諒,請勿挪作商業用途,並著明出處。


使用NSXMLParser來解析一份XML文件的必要步驟是很直觀的。它需要完成下列步驟:

  1. Locate the XML.
  2. 創建並初始化NSXMLParser的實例,並確認你設定好了委任。
  3. 實作你有興趣的委任方法。
  4. 處理任何解析錯誤
 以下就一項一項解釋。

  1.  Locate the XML.
    表一展示了讓使用者從檔案系統瀏覽(file-system browser(NSOpenPanel))中選取一個XML檔案的程式碼。

    - (void)openXMLFile {
     
        NSArray *fileTypes = [NSArray arrayWithObject:@"xml"];
        NSOpenPanel *oPanel = [NSOpenPanel openPanel];
        NSString *startingDir = [[NSUserDefaults standardUserDefaults] objectForKey:@"StartingDirectory"];
        if (!startingDir)
            startingDir = NSHomeDirectory();
        [oPanel setAllowsMultipleSelection:NO];
        [oPanel beginSheetForDirectory:startingDir file:nil types:fileTypes
          modalForWindow:[self window] modalDelegate:self
          didEndSelector:@selector(openPanelDidEnd:returnCode:contextInfo:)
          contextInfo:nil];
    }
     
    - (void)openPanelDidEnd:(NSOpenPanel *)sheet returnCode:(int)returnCode contextInfo:(void *)contextInfo {
        NSString *pathToFile = nil;
        if (returnCode == NSOKButton) {
            pathToFile = [[[sheet filenames] objectAtIndex:0] copy];
        }
        if (pathToFile) {
            NSString *startingDir = [pathToFile stringByDeletingLastPathComponent];
            [[NSUserDefaults standardUserDefaults] setObject:startingDir forKey:@"StartingDirectory"];
            [self parseXMLFile:pathToFile];
        }
    }

    雖然一份XML檔案是一般的情況,XML的資源(resource)也許不是一份檔案。你可以從像是屬性列表物件(property-list object,像NSDictionary)或是透過網路(network)的位元串流(stream of bytes)接收到XML。像這樣的情況,你必須在初始化NSXMLParser實例前(參考下列步驟)先轉換XML的形式成NSData物件。
  2. 創建並初始化NSXMLParser的實例,並確認你設定好了委任。

    表二:創建和初始化NSXMLParser實例

    - (void)parseXMLFile:(NSString *)pathToFile {
        BOOL success;
        NSURL *xmlURL = [NSURL fileURLWithPath:pathToFile];
        if (addressParser) // addressParser is an NSXMLParser instance variable
            [addressParser release];
        addressParser = [[NSXMLParser alloc] initWithContentsOfURL:xmlURL];
        [addressParser setDelegate:self];
        [addressParser setShouldResolveExternalEntities:YES];
        success = [addressParser parse]; // return value not used
                    // if not successful, delegate is informed of error
    }

    在這個方法,客制物件(client object)轉換XML檔案路徑成一個NSURL物件,然後使用那個物件去以initWithContentsOfURL:方法初始化NSXMLParser的實例。它也將它自己設定成委任,並讓parser知道他要去解決外部實體(resolve external entity)(像是外部DTD宣告)。其他的NSXMLParser方法讓你設定多個命名空間相關選擇。最後,客制物件將parse送到NSXMLParser實例來開始解析XML。

    若XML不是檔案的形式,你要把它轉換成一個NSData物件,然後使用initWithData:初始子來出初始化它:

    addressParser = [[NSXMLParser alloc] initWithData:xmlData];

  3. 實作你有興趣的委任方法。
    當NSXMLParser物件解析XML時,它為它所遇到的每一個XML建構送訊息到它的委任(但只有委任實作了相關方法時才會如此)。這些方法的實作隨著建構的不同而改變:DTD宣告、命名空間首字母(namespace prefix)、元素等等。元素是最XML建構裡面最普遍的種類,參考Handling XML Elements and Attributes。

    所有的解析操作開始於委任接收到parserDidStartDocument:方法,並結束於委任接收到parserDidEndDocument:方法(當然,這也要委任有實作這些方法)。前一個方法提供分配空間(allocating)和設定解析操作所需要的資源(resource),後一個方法是適合去釋放那些資源和適當的處理任何結果的地方。
     
  4. 處理任何解析錯誤。

    若parser遇到錯誤,它會停止解析並且喚起委任方法
    parser:parseErrorOccurred:。實作這個方法去說明錯誤和通知使用者。(所有的parser錯誤都不能回復),參考“Handling Parsing Errors。
    當你解析XML時,記憶體管理變的很重要。處理XML常常要你去創建很多物件,你不應讓這些物件在用完後仍佔據記憶體(accumulate in memory past their span of usefulness)。一個處理這些產生的物件的技巧是,讓委任再每個委任方法十作開始時去創建局部自動釋放池,並在回傳前釋放自動釋放池。NSXMLParser為它所創建的每個物件管理記憶體,並傳送到委任。

     

留言