所以我正在研究一个项目,该项目将允许用户进行多个不同的测验。
我的XML(在线托管)具有以下格式:
<questions>
<question>
<clue> sample clue 1 </clue>
<correct_answer>2</correct_answer>
<enumeration>1</enumeration>
<info> sample info 1 </info>
<location_clue>Sample locationClue (5,5)</location_clue>
<option_a>Ans1</option_a>
<option_b>Ans2</option_b>
<option_c>Ans3</option_c>
</question>
<question>
<clue> sample clue 2 </clue>
<correct_answer>3</correct_answer>
<enumeration>2</enumeration>
<info> sample info 2 </info>
<location_clue>Sample locationClue (4,2)</location_clue>
<option_a>Ans1</option_a>
<option_b>Ans2</option_b>
<option_c>Ans3</option_c>
</question>
</questions>
我的解析器启动看起来像这样:
if let urlString = URL(string: "realURL goes here.xml -- This has an actual url in my code obviously.")
{
if let parser = XMLParser(contentsOf: urlString)
{
parser.delegate = self
parser.parse()
}
}
parserDidStartElement:
func parser(_ parser: XMLParser, didStartElement elementName: String, namespaceURI: String?, qualifiedName qName: String?, attributes attributeDict: [String : String] = [:])
{
thisName = elementName
if thisName == "hunt"
{
}
}
ParserFoundCharacter:
func parser(_ parser: XMLParser, foundCharacters string: String)
{
let data = string.trimmingCharacters(in: CharacterSet.whitespacesAndNewlines)
if data.count != 0
{
switch thisName
{
case "clue": questionClue = data
break
case "info": questionInfo = data
break
case "location_clue": locationClue = data
break
case "option_a": questionAnswerA = data
break
case "option_b": questionAnswerB = data
break
case "option_c": questionAnswerC = data
default:
break
}
}
}
这是HuntDetail.swift类,它创建一个名为QUIZ的脚本,该脚本内部目前有4个变量,即问题,答案A,答案B和答案C:
import Foundation
struct QUIZ {
var question = ""
var answerA = ""
var answerB = ""
var answerC = ""
}
从本质上讲,该应用程序将允许用户进行多项选择测验。选择答案后,界面顶部的进度条将显示当前测验的进度。
我想知道是否可以在一个数组内存储以下内容:clue,info,location_clue,option_a,b,c ...,我将从该数组开始制定实际的测验功能。 / p>
就目前而言,该应用程序将仅显示前面提到的数据的最后一个元素。
我知道这很长,可能很难理解我要做什么,但是如果有人可以提供帮助,将不胜感激。还应该指出的是,是的,我对Swift和iOS的整体开发还很陌生。
答案 0 :(得分:0)
是的,尽管我已经有一段时间没有使用XMLParser了,但是您可以轻松地做到这一点。
注意::在下面的代码中,我将您的QUIZ
重命名为Question
,因为该结构代表一个问题,而不是整个测验(问题列表)>
因此,您希望在解析每个项目时使用一个空数组:
var quiz = [Question]() // quiz is a list of questions.
然后您要跟踪当前正在处理的问题
var currentQuestion: Question?
因此,每次您开始和结束一个Question元素时,您都知道您已经完成了对单个问题的解析,因此将其添加到列表中。
func parser(_ parser: XMLParser, didStartElement elementName: String, namespaceURI: String?, qualifiedName qName: String?, attributes attributeDict: [String : String] = [:]) {
if elementName == "Question" {
currentQuestion = Question()
}
}
func parser(_ parser: XMLParser, didEndElement elementName: String, namespaceURI: String?, qualifiedName qName: String?) {
if elementName == "Question", let question = currentQuestion {
quiz.append(question)
}
}
因此,您只是从上至下解析XML文档。一旦遇到一个开头的Question元素,就创建一个Question对象,填充其余的内容,然后在遇到一个封闭的Question元素时,将当前问题添加到列表中。
在文档末尾,您的测验变量应包含文档中的所有问题。
编辑:
因此,我必须进行一些更改,foundCharacters可以分成几部分,因此我们需要对其进行跟踪。
这是一个工作场所,它会返回2个问题(基于上面的示例XML)。答案C始终为空白,这似乎是因为换行符,并且修剪会剪切文本,您可能需要先删除换行符,然后再修剪空格,但是此代码将为您提供一个良好的开始。
import Foundation
let xmlData = """
<questions>
<question>
<clue> sample clue 1 </clue>
<correct_answer>2</correct_answer>
<enumeration>1</enumeration>
<info> sample info 1 </info>
<location_clue>Sample locationClue (5,5)</location_clue>
<option_a>Ans1</option_a>
<option_b>Ans2</option_b>
<option_c>Ans3</option_c>
</question>
<question>
<clue> sample clue 2 </clue>
<correct_answer>3</correct_answer>
<enumeration>2</enumeration>
<info> sample info 2 </info>
<location_clue>Sample locationClue (4,2)</location_clue>
<option_a>Ans1</option_a>
<option_b>Ans2</option_b>
<option_c>Ans3</option_c>
</question>
</questions>
""".data(using: .utf8)!
struct Question {
var question: String?
var clue: String?
var info: String?
var locationClue: String?
var answerA: String?
var answerB: String?
var answerC: String?
}
class MySuperXMLParser: NSObject, XMLParserDelegate {
private let parser: XMLParser
private var quiz = [Question]()
private var currentQuestion: Question?
private var currentElement: String?
private var foundCharacters = ""
init(data: Data) {
parser = XMLParser(data: data)
super.init()
parser.delegate = self
}
func parse() -> [Question] {
parser.parse()
return quiz
}
func parser(_ parser: XMLParser, didStartElement elementName: String, namespaceURI: String?, qualifiedName qName: String?, attributes attributeDict: [String : String] = [:]) {
if elementName == "question" {
currentQuestion = Question()
}
print("Started element: \(elementName)")
currentElement = elementName
}
func parser(_ parser: XMLParser, foundCharacters string: String) {
print("found characters: \(string)")
foundCharacters += string
}
func parser(_ parser: XMLParser, didEndElement elementName: String, namespaceURI: String?, qualifiedName qName: String?) {
print("ended element: \(elementName), text = \(foundCharacters)")
let text = foundCharacters.trimmingCharacters(in: CharacterSet.whitespacesAndNewlines)
switch currentElement
{
case "clue":
currentQuestion?.clue = text
break
case "info":
currentQuestion?.info = text
break
case "location_clue":
currentQuestion?.locationClue = text
break
case "option_a":
currentQuestion?.answerA = text
break
case "option_b":
currentQuestion?.answerB = text
break
case "option_c": currentQuestion?.answerC = text
default:
break
}
foundCharacters = ""
if elementName == "question", let question = currentQuestion {
print("adding question: \(question)")
quiz.append(question)
}
}
}
let parser = MySuperXMLParser(data: xmlData)
let quiz = parser.parse()
print(quiz.count, quiz)
答案 1 :(得分:0)
如果您不介意使用外部库,则可以尝试XMLMapper。
只需使用以下模型类:
class Questions: XMLMappable {
var nodeName: String!
var questions: [Question]?
required init(map: XMLMap) {
}
func mapping(map: XMLMap) {
questions <- map["question"]
}
}
class Question: XMLMappable {
var nodeName: String!
var clue: String?
var correct_answer: Int?
var enumeration: Int?
var info: String?
var location_clue: String?
var option_a: String?
var option_b: String?
var option_c: String?
required init(map: XMLMap) {
}
func mapping(map: XMLMap) {
clue <- map["clue"]
correct_answer <- map["correct_answer"]
enumeration <- map["enumeration"]
info <- map["info"]
location_clue <- map["location_clue"]
option_a <- map["option_a"]
option_b <- map["option_b"]
option_c <- map["option_c"]
}
}
并通过在map(XMLString:)
中调用XMLMapper
函数来映射XML:
let object = XMLMapper<Questions>().map(XMLString: xmlString)
print(object?.questions?.first?.clue ?? "nil")
希望这会有所帮助。