此份文件為個人學習事件驅動XML程式的翻譯,內文請參考蘋果官方文件,若有翻譯錯誤請見諒,請勿挪作商業用途,並著明出處。
一般而言,當你解析XML文件時, 大部分的處理過程包含了元素和與元素有關的東西, 像是屬性和文本(textual)內容。 元素掌握了XML文件中大部分的資訊。 當NSXMLParser物件通過(traverse) XML文件裡面的一個元素時, 它至少會依照下面所述的次序送出三個不同的訊息到它的委任:
foundCharacters:訊息,然而,若字符( character)只有空白字符(space,
new line, tab和類似的字符)沒有其他東西, parser會送出parser: foundIgnorableWhitespace( 而不是parser:foundCharacters:)。
當你解析XML元素時,有一個高等技術, 就是你可以在多個委任中切換處理則任, 每一個委任都知道怎樣處理元素的一個特定種類。 可以參考Using
Multiple Delegates。
一個常見的處理元素的策略是去映照它們—至少在更高的巢狀層級— 到物件。根元素和其他頂級(top
level) 元素常等同於在Cocoa裡面由NSDictionary和NS Array物件表示的收集。 其他的元素可能會立即映照到一或多個應用程式的客製模型物件( application’s
custom modal object)。
然而,不是所有的元素都最好要表示成物件。有些低階和特別的”葉 (leaf)”元素更邏輯的被視作它們的父元素的特性( 若那元素映照到一個物件)。當然, 你可能製作任何元素的實際屬性之對應的物件的一個特性( property)(亦即,一個實例變數)。
儘管有這些建議,但並沒有現成的映照公式, 事實上你的應用程式可能不需執行任何元素到物件之間的映照。 這些設計決定需要一些想法和對於XML結構的熟悉。
案並且轉換這資訊到通訊錄物件(Address
Book object)( ABPerson和ABMultipleValue), 這些物件可以加到指定的使用者地址資料庫(address
database)。XML的一部分就像下面這樣:
表一:XML的範例
來看看前三個元素是怎麼處理的吧。 當parser首先遇到這些元素,它呼喚委任的parser: didStartElement:namespaceURI: qualifiedName:attributes:方法。 對前兩個元素,委任創建一個相等的物件,對第三個元素( lastName),委任設定第二個物件的一個適當的特性。 表二顯示了對於前三個元素開始標籤的委任實作。
表二:實作parser:didStartElement: namespaceURI:qualifiedName: attribute:
委任識別在(elementName)中傳遞的元素, 然後根據以下原則處理它:
去追蹤目前的元素在parser遍歷(parser’s
traversal)它之後。一個重要的理由是parser: foundCharacters:的語義, 很可能在下一個委任方法中呼喚。對同一個元素, 這個方法可以被呼喚好幾次。在這個方法, 委任應該要附加上元素目前累積的傳入(pass
in)的字符(characters)。為此目的, NSMutableString的appendString: 方法很有用,參考表三。
表三:實作parser:foundCharacters:
程式碼使用了實例變數(currentStringValue) 來追蹤並聚集(gather)目前元素的內容。 若parser在元素內容中遇到一些空白字符, 它會傳送訊息parser: foundIgnorableWhitespace:給委任, 讓委任有機會去維持(retain)任何空白字符( 像是tab或是換行)。
最後,當parser遇到元素的結尾標籤, 它會喚起委任方法parser:didEndElement: namespaceURI:qualifiedName:。 表示表示了範例程式碼中的委任採取的方法。
表四:實作parser:didEndElement: namespaceURI:qualifiedName:
若委任決定結尾標籤是person元素的, 它加入ABPerson物件到addresses陣列並且釋放A BPerson物件。若結尾物件是lastName元素的( 舉例來說),委任使用ABRecord的setValue: forProperty: 方法去設定ABPerson物件中適當的特性( ABPerson是ABPerson的超類)。最後, 持有累積的元素內容的實例變數( currentStringValue)會被釋放。
在這假設的情況中, 屬性允許解析XML的應用程式儲存創建的Address
Book information在指定的多重使用者系統內的使用者目錄( directory)。 NSXMLParser物件表示到委任的一個元素的屬性pars er:didStartElement: namespaceURI:qualifiedName: attributes:
方法內最後一個引數內的字典(亂翻一通)
表五顯示範例中的委任如何處理owner屬性。
表五:處理元素的屬性
委任使用屬性名稱(owner)做為鍵, 從attributeDict字典擷取擁有者使用者名稱。 然後它喚起一個聯繫owner和imported
Address Book data的隱式方法
一般而言,當你解析XML文件時,
- parser:didStartElement:
namespaceURI:qualifiedName: attributes: - parser:foundCharacters:
- parser:didEndElement:
namespaceURI:qualifiedName:
當你解析XML元素時,有一個高等技術,
Design Considerations
在物件導向環境,像是Cocoa,然而,不是所有的元素都最好要表示成物件。有些低階和特別的”葉
儘管有這些建議,但並沒有現成的映照公式,
Handling an Element: An Example
下面討論中提到的範例程式碼處理一個包含人和地址資訊的XML檔表一:XML的範例
<?xml version="1.0" encoding="UTF-8"?> |
<!DOCTYPE addresses SYSTEM "addresses.dtd"> |
<addresses owner="swilson"> |
<person> |
<lastName>Doe</lastName> |
<firstName>John</firstName> |
<phone location="mobile">(201) 345-6789</phone> |
<email>jdoe@foo.com</email> |
<address> |
<street>100 Main Street</street> |
<city>Somewhere</city> |
<state>New Jersey</state> |
<zip>07670</zip> |
</address> |
</person> |
<!-- more person elements go here --> |
</addresses> |
來看看前三個元素是怎麼處理的吧。
表二:實作parser:didStartElement:
- (void)parser:(NSXMLParser *)parser didStartElement:(NSString *)elementName namespaceURI:(NSString *)namespaceURI qualifiedName:(NSString *)qName attributes:(NSDictionary *)attributeDict { |
if ( [elementName isEqualToString:@"addresses"]) { |
// addresses is an NSMutableArray instance variable |
if (!addresses) |
addresses = [[NSMutableArray alloc] init]; |
return; |
} |
if ( [elementName isEqualToString:@"person"] ) { |
// currentPerson is an ABPerson instance variable |
currentPerson = [[ABPerson alloc] init]; |
return; |
} |
if ( [elementName isEqualToString:@"lastName"] ) { |
[self setCurrentProperty:kABLastNameProperty]; |
return; |
} |
// .... continued for remaining elements .... |
} |
委任識別在(elementName)中傳遞的元素,
- 若它是一個地址元素(addresses
element)(根元素, root element),
它創建可變更的陣列去持有ABPerson物件, 這個可變陣列做為實例變數來持有。 - 若它是一個個人元素(person
element),它創建一個ABPerson物件,
這物件以名為currentPerson的實例變數來持有。 - 若是lastName元素,
它設定一個實例變數來持有目前的通訊錄特性(Address Book property),這個值是一個宣告在Address Book framework 的enum常數。
表三:實作parser:foundCharacters:
- (void)parser:(NSXMLParser *)parser foundCharacters:(NSString *)string { |
if (!currentStringValue) { |
// currentStringValue is an NSMutableString instance variable |
currentStringValue = [[NSMutableString alloc] initWithCapacity:50]; |
} |
[currentStringValue appendString:string]; |
} |
程式碼使用了實例變數(currentStringValue)
最後,當parser遇到元素的結尾標籤,
表四:實作parser:didEndElement:
- (void)parser:(NSXMLParser *)parser didEndElement:(NSString *)elementName namespaceURI:(NSString *)namespaceURI qualifiedName:(NSString *)qName { |
// ignore root and empty elements |
if (( [elementName isEqualToString:@"addresses"]) || |
( [elementName isEqualToString:@"address"] )) return; |
if ( [elementName isEqualToString:@"person"] ) { |
// addresses and currentPerson are instance variables |
[addresses addObject:currentPerson]; |
[currentPerson release]; |
return; |
} |
NSString *prop = [self currentProperty]; |
// ... here ABMultiValue objects are dealt with ... |
if (( [prop isEqualToString:kABLastNameProperty] ) || |
( [prop isEqualToString:kABFirstNameProperty] )) { |
[currentPerson setValue:(id)currentStringValue forProperty:prop]; |
} |
// currentStringValue is an instance variable |
[currentStringValue release]; |
currentStringValue = nil; |
} |
若委任決定結尾標籤是person元素的,
Handling an Attribute
在表一中的XML範例的addresses元素包含了以下屬性:<addresses owner="swilson">
在這假設的情況中,
表五顯示範例中的委任如何處理owner屬性。
表五:處理元素的屬性
- (void)parser:(NSXMLParser *)parser didStartElement:(NSString *)elementName namespaceURI:(NSString *)namespaceURI qualifiedName:(NSString *)qName attributes:(NSDictionary *)attributeDict { |
if ( [elementName isEqualToString:@"addresses"]) { |
// addresses is an NSMutableArray instance variable |
if (!addresses) |
addresses = [[NSMutableArray alloc] init]; |
NSString *thisOwner = [attributeDict objectForKey:@"owner"]; |
if (thisOwner) |
[self setOwner:thisOwner forAddresses:addresses]; |
return; |
// ... continued ... |
}} |
委任使用屬性名稱(owner)做為鍵,
留言
張貼留言