arrays - 将 XML 数据存储为数组,Swift
问题描述
所以我正在研究一个允许用户做多个不同测验的项目。
我的 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 个变量,question、answerA、answerB 和 answerC:
import Foundation
struct QUIZ {
var question = ""
var answerA = ""
var answerB = ""
var answerC = ""
}
本质上,该应用程序将允许用户进行多项选择测验。选择答案后,界面顶部的进度条将指示他们通过当前测验的进度。
我想知道是否可以将值:线索、信息、位置线索、选项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 文档。一旦你遇到一个开始的问题元素,创建一个问题对象,填写其余部分,然后当你遇到一个结束的问题元素时,将当前问题添加到列表中。
在文档末尾,您的 quiz 变量应该包含文档中的所有问题。
编辑:
所以我不得不做一些改变,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)
推荐阅读
- linux - 从脚本的输出中提取一个值并存储在一个变量 linux 中?
- python - 熊猫 read_sql 的 Python 编码问题
- java - GridBagLayout(同一行)
- javascript - 尝试使用 Math.random 和过滤器填充 16 个随机图像
- javascript - 正则表达式接受字母数字字符且只有一个 @ 符号
- python - 从粒子云请求事件时程序不终止
- apache-spark - 在 spark-csv 创建的数据帧上获取 java.lang.NumberformatException
- php - 用于删除和重新插入的嵌套 foreach 仅插入最后一个元素
- html - Bootstrap 导航栏固定顶部
- sql - 如何以最简单的方式在 SQL Developer 中定义和使用 Oracle SQL Script 中的变量