所以我正在开发一个项目,该项目将允许用户进行多个不同的测验。
我的 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()
}
}
解析器DidStartElement:
func parser(_ parser: XMLParser, didStartElement elementName: String, namespaceURI: String?, qualifiedName qName: String?, attributes attributeDict: [String : String] = [:])
{
thisName = elementName
if thisName == "hunt"
{
}
}
解析器发现字符:
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 的 scruct,该 scruct 内部当前有 4 个变量,question、answerA、answerB 和 answerC:
import Foundation
struct QUIZ {
var question = ""
var answerA = ""
var answerB = ""
var answerC = ""
}
本质上,该应用程序将允许用户进行多项选择测验。选择答案后,界面顶部的进度条将指示当前测验的进度。
我想知道是否可以将以下值存储在数组内:线索,信息,location_clue,option_a,b,c ...,从该数组我将开始制定实际的测验功能。
就目前而言,应用程序将仅显示前面提到的数据的最后一个元素。
我知道这很长,可能很难理解我想要做什么,但如果有人可以提供帮助,我将不胜感激。还应该指出的是,是的,我对 Swift 和整个 iOS 开发还相当陌生。
最佳答案
是的,您可以相当轻松地完成此操作,尽管我已经有一段时间没有使用 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 文档。一旦遇到开始问题元素,创建一个问题对象,填写其余内容,然后当遇到结束问题元素时,将当前问题添加到列表中。
在文档末尾,您的测验变量应包含文档中的所有问题。
编辑:
所以我必须做一些改变,找到的角色可以分为几部分,所以我们需要跟踪它。
这是一个工作 Playground ,它返回 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)
关于arrays - 将 XML 数据存储为数组,Swift,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/50950450/