我正在开展一个项目,我将XML响应转换为对象的实例。为了这个问题,根元素被映射到“参数”,子元素被映射到“子参数”,类设置就像这样。
class MyClass : NSObject {
var Parameter = Parameter()
}
class Parameter: NSObject {
var Subparameter = String()
}
我的问题是这个...如何使用setValue(value,key)设置MyClass.Parameter.Subparameter的值?
提前感谢您的协助。
答案 0 :(得分:1)
如果你的类是NSObject
的子类,那么你喜欢键值编码(KVC),你可以object.setValue(forKey:)
。
如果您使用具有子元素的某些元素处理XML,那么诀窍就是如何让解析器跟踪执行setValue(forKey:)
的对象。我个人经常会维护一堆对象:
考虑这个XML:
<people>
<person>
<name>Rob</name>
<address>
<address1>1 Main Street</address1>
<address2 />
<city>Pasadena</city>
<state>CA</state>
</address>
</person>
<person>
<name>Rachel</name>
<address>
<address1>1 Broadway</address1>
<address2>Apt 1</address2>
<city>New York</city>
<state>NY</state>
</address>
</person>
</people>
考虑这个类层次结构:
class Person : NSObject {
var name: String?
var address: Address?
}
class Address: NSObject {
var address1: String?
var address2: String?
var city: String?
var state: String?
}
因此,当我输入<person>
时,我将Person
对象添加到我的堆栈中。当我退出</person>
时,我从堆栈中弹出Person
并相应地更新父对象。同样,当我输入并存在<address>
和</address>
时,我将Address
个对象从我的堆栈中推出并再次弹出,再次相应地更新父对象。使用这种模式,在任何给定的时间点,堆栈中的最后一项始终是&#34;当前&#34;对象,所以每当遇到Person
或Address
之外的其他元素时,我只是用我收到的任何字符串值更新当前对象的值。
因此,您可以使用以下方法解析它:
var results: [Person]?
private var objectStack = [NSObject]()
private var currentString: String?
func parser(parser: NSXMLParser, didStartElement elementName: String, namespaceURI: String?, qualifiedName qName: String?, attributes attributeDict: [String : String]) {
if elementName == "people" {
objectStack = [Person]()
} else if elementName == "person" {
objectStack.append(Person())
} else if elementName == "address" {
objectStack.append(Address())
} else {
currentString = String()
}
}
func parser(parser: NSXMLParser, foundCharacters string: String) {
currentString? += string
}
func parser(parser: NSXMLParser, didEndElement elementName: String, namespaceURI: String?, qualifiedName qName: String?) {
if let foundString = currentString {
objectStack.last?.setValue(foundString, forKey: elementName)
currentString = nil
} else if let lastObject = objectStack.last where lastObject is Address {
objectStack.removeLast()
if objectStack.isEmpty {
results = lastObject as? [Person]
} else {
objectStack.last?.setValue(lastObject, forKey: elementName)
}
}
}
func parser(parser: NSXMLParser, parseErrorOccurred parseError: NSError) {
print(parseError)
}
现在这是一个基本的例子。例如,我不检查当前对象是否具有该elementName
的属性,因此如果XML包含的元素名称与对象不对应,则上述内容将崩溃属性。我也不检查element属性的类型来对已解析的字符串值进行适当的转换。所有这些都很容易添加,但我希望尽可能简洁。
但它说明了基本的想法:你需要
didEndElement
; didStartElement
中进行特殊处理,以了解是否要实例化自定义对象并将其推送到堆栈,或者是否要解析某些文本值以仅更新当前对象; didEndElement
中进行特殊处理,以了解您是否正在更新自定义对象的值,或者您是否已完成某些自定义对象,将其从堆栈中弹出并更新父自定义对象中的某些值(现在在堆栈的末尾)。如果这个堆栈概念太混乱,你可以通过跟踪各种属性来完成同样的事情,具体取决于你碰巧在什么级别的XML树。我个人认为堆栈模型很有吸引力。
无论如何,一旦你负责跟踪你在XML树中的位置,你就可以setValue(forKey:)
来更新一个顶级元素或一些子元素的值。