I am currently trying to parse a rest xml api response from a STANDS4 api...
the XML file would look something like this:
<results>
<result>
<quote>
To be free it is not enough to beat the system, one must beat the system every day.
</quote>
<author>Anonymous</author>
</result>
</results>
What I want to do is be able to print out the XML response and be able to assign the quote and author to a UILabel. What I currently have is the below code (I have my user ID and my token ID)
import UIKit
class ViewController: UIViewController,NSXMLParserDelegate {
var strXMLData:String = ""
var currentElement:String = ""
var passData:Bool=false
var passName:Bool=false
var parser = NSXMLParser()
#IBOutlet weak var lblNameData: UILabel!
override func viewDidLoad() {
super.viewDidLoad()
let url:String="http://www.stands4.com/services/v2/quotes.php?uid=youridhere&tokenid=youridherezf&searchtype=AUTHOR&query=Albert+Einstein"
let urlToSend: NSURL = NSURL(string: url)!
// Parse the XML
parser = NSXMLParser(contentsOfURL: urlToSend)!
parser.delegate = self
let success:Bool = parser.parse()
if success {
print("parse success!")
print(strXMLData)
lblNameData.text=strXMLData
} else {
print("parse failure!")
}
}
override func didReceiveMemoryWarning() {
super.didReceiveMemoryWarning()
// Dispose of any resources that can be recreated.
}
func parser(parser: NSXMLParser, didStartElement elementName: String, namespaceURI: String?, qualifiedName qName: String?, attributes attributeDict: [String : String]) {
currentElement=elementName;
if(elementName=="id" || elementName=="name" || elementName=="cost" || elementName=="description")
{
if(elementName=="name"){
passName=true;
}
passData=true;
}
}
func parser(parser: NSXMLParser, didEndElement elementName: String, namespaceURI: String?, qualifiedName qName: String?) {
currentElement="";
if(elementName=="id" || elementName=="name" || elementName=="cost" || elementName=="description")
{
if(elementName=="name"){
passName=false;
}
passData=false;
}
}
func parser(parser: NSXMLParser, foundCharacters string: String) {
if(passName){
strXMLData=strXMLData+"\n\n"+string
}
if(passData)
{
print(string)
}
}
func parser(parser: NSXMLParser, parseErrorOccurred parseError: NSError) {
NSLog("failure error: %#", parseError)
}
}
I currently get the response that the parse was a success but nothing is printed out. I got the above code from this tutorial:
http://ashishkakkad.com/2014/10/xml-parsing-in-swift-language-ios-9-nsxmlparser/
so there is most likely some changes I need to make to work with my current API, but I'm not sure what exactly to do.
Any help is appreciated!
Your first problem is that your XMLParsing functions never look for the proper element names (assuming your example xml is exactly what you are getting). Your XML parsing is looking for "id", "name", "cost", or "description". Your example XML provides "quote" and "author". You need to debug through the XML parsing functions and get a handle on what they are actually doing before using them. Then you should be good to go.
Related
i have to extract and parse json from a text file, i know how to parse json but i'm just unable to extract it correctly from xml format. this is my xml which contains json.
<Data>
<Persons>[{"ID":"2","Name":"Catagory 1"},{"ID":"3","Name":"Catagory 2”</Persons>
<class>[{"ID":"3","Name":"WEAVING”}]</class>
</Data>
what i want is to get json sepratly with its tags, like for example.
"Persons":"[{"ID":"2","Name":"Catagory 1"},{"ID":"3","Name":"Catagory 2”}]"
Please find the sample code for parsing xml below:
import UIKit
import Foundation
class ViewController: UIViewController {
var parser:XMLParser?
var foundChars: String = ""
var personsStr: String = ""
override func viewDidLoad() {
super.viewDidLoad()
parseXML()
// Do any additional setup after loading the view, typically from a nib.
}
func parseXML() {
let str: NSString = "<Data><Persons>[{\"ID\":\"2\",\"Name\":\"Catagory 1\"},{\"ID\":\"3\",\"Name\":\"Catagory 2\"}]</Persons><class>[{\"ID\":\"3\",\"Name\":\"WEAVING\"}]</class></Data>"
if let data = str.data(using: String.Encoding.utf8.rawValue) {
parser = XMLParser.init(data: data)
parser!.delegate = self
parser!.parse()
}
}
}
extension ViewController: XMLParserDelegate {
public func parserDidEndDocument(_ parser: XMLParser) {
debugPrint("Person str is:: " + self.personsStr)
//TODO: You have to build your json object from the PersonStr now
}
func parser(_ parser: XMLParser, foundCharacters string: String) {
self.foundChars = self.foundChars + string
}
func parser(_ parser: XMLParser, didEndElement elementName: String, namespaceURI: String?, qualifiedName qName: String?) {
debugPrint("end element::" + elementName)
if (elementName == "Persons") {
self.personsStr = self.foundChars
}
self.foundChars = ""
}
}
Here is a part of my URL
<cities>
<country name="Абхазия">
<city id="37188" region="27028" head="" type="3" country="Абхазия" part="" resort="" climate="">Новый Афон</city>
<city id="37178" region="10282" head="" type="3" country="Абхазия" part="" resort="" climate="">Пицунда</city>
<city id="37187" region="37187" head="" type="3" country="Абхазия" part="" resort="" climate="">Гудаута</city>
<city id="37172" region="10280" head="" type="3" country="Абхазия" part="" resort="" climate="">Гагра</city>
<city id="37189" region="10281" head="0" type="3" country="Абхазия" part="" resort="0" climate="">Сухум</city>
</country>
User types the name of the city, for example: "Пицунда" and I want to get its id. For "Пицунда" id is "10282".
Below I've posted my not-working code.
var parser: NSXMLParser!
var city: String = String()
var ifDirOK = false
var ifCityNameOK = false
override func viewDidLoad() {
super.viewDidLoad()
let url: NSURL = NSURL(string: "https://pogoda.yandex.ru/static/cities.xml")!
parser = NSXMLParser(contentsOfURL: url)
parser.delegate = self
parser.parse()
}
override func didReceiveMemoryWarning() {
super.didReceiveMemoryWarning()
// Dispose of any resources that can be recreated.
}
func parser(parser: NSXMLParser!, didStartElement elementName: String!, namespaceURI: String!, qualifiedName qName: String!, attributes attributeDict: [NSObject : AnyObject]!) {
//let cityID = attributeDict ["id"] as? NSString
if (elementName == "city"){
ifDirOK = true
}
}
func parser(parser: NSXMLParser!, foundCharacters string: String!) {
var data = string.stringByTrimmingCharactersInSet(NSCharacterSet.whitespaceAndNewlineCharacterSet())
if (data == city){
ifCityNameOK = true
}
}
func parser(parser: NSXMLParser!, foundAttributeDeclarationWithName attributeName: String!, forElement elementName: String!, type: String!, defaultValue: String!) {
if (ifDirOK && ifCityNameOK){
println("\(attributeName)")
}
}
func parser(parser: NSXMLParser!, didEndElement elementName: String!, namespaceURI: String!, qualifiedName qName: String!) {
}
After all, I want to pass id to another URL file (export.yandex.ru/weather-ng/forecasts/{id of the city}.xml) and parse it. Do I need to create another Swift class and somehow connect it with first one?
Building a dictionary of [city:id] can be a solution for you.
I have implemented a simple solution based on the article about lifecycle of NSXMLParser at http://www.codeproject.com/Articles/248883/Objective-C-Fundamentals-NSXMLParser .
Following method is called when when an element is starting.
You can retrieve city id attribute and save it in an instance level variable so that you can use it in the next method.
func parser(parser: NSXMLParser, didStartElement elementName: String, namespaceURI: String?, qualifiedName qName: String?, attributes attributeDict: [NSObject : AnyObject])
And then, Following method is called when the parser see anything between starting and ending.
func parser(parser: NSXMLParser!, foundCharacters string: String!)
So, you can get the city name from here.
Now we have city id and city name to add a new item into the [city:id] dictionary.
Once you build the dictionary, searching would be very simple.
here is my working test code.
class ViewController: UIViewController ,NSXMLParserDelegate{
var parser: NSXMLParser!
var city: String = String()
var ifDirOK = false
var ifCityNameOK = false
var element : String?
var value: String=String()
var dic = Dictionary<String,String>()
var currentCityId:String?
#IBOutlet weak var result: UILabel!
#IBOutlet weak var search: UITextField! //search text
#IBAction func ActionGoGetIt(sender: AnyObject) {
self.result.text=dic[self.search.text]
}
override func viewDidLoad() {
super.viewDidLoad()
let url: NSURL = NSURL(string: "https://pogoda.yandex.ru/static/cities.xml")!
parser = NSXMLParser(contentsOfURL: url)
parser.delegate = self
parser.parse()
}
override func didReceiveMemoryWarning() {
super.didReceiveMemoryWarning()
// Dispose of any resources that can be recreated.
}
func parser(parser: NSXMLParser, didStartElement elementName: String, namespaceURI: String?, qualifiedName qName: String?, attributes attributeDict: [NSObject : AnyObject]) {
element = elementName
if (element == "city"){
ifDirOK = true
let cityID = attributeDict ["id"] as? NSString
self.currentCityId = cityID as? String
}
}
func parser(parser: NSXMLParser!, foundCharacters string: String!) {
var data = string.stringByTrimmingCharactersInSet(NSCharacterSet.whitespaceAndNewlineCharacterSet())
if (!data.isEmpty){
if (element == "city"){
dic[data] = self.currentCityId as String?
}
}
}
func parser(parser: NSXMLParser, foundAttributeDeclarationWithName attributeName: String, forElement elementName: String, type: String?, defaultValue: String?) {
if (ifDirOK && ifCityNameOK){
println("\(attributeName)")
}
}
func parser(parser: NSXMLParser, didEndElement elementName: String, namespaceURI: String?, qualifiedName qName: String?) {
}
}
I am having an issue in which I am parsing a String value from an API and I am trying to assign it to an UILabel. I have tested updating the label in the exact same position as it is now by setting the label (lblNamedata) to a String using the format:
self.lblNameData.text = "hello"
and it has worked fine.
I currently have:
if success {
print("parse success!")
print(strXMLData)
dispatch_async(dispatch_get_main_queue(), { () -> Void in
self.lblNameData.text=self.strXMLData
})
} else {
print("parse failure!")
}
and this isn't working.
Below is my complete current code:
import UIKit
class ViewController: UIViewController,NSXMLParserDelegate {
var strXMLData:String = ""
var currentElement:String = ""
var passData:Bool=false
var passName:Bool=false
var parser = NSXMLParser()
#IBOutlet weak var lblNameData: UILabel!
override func viewDidLoad() {
super.viewDidLoad()
let url:String="http://www.stands4.com/services/v2/quotes.php?uid=idhere&tokenid=tokenhere&searchtype=xxxx&query=xxxx"
let urlToSend: NSURL = NSURL(string: url)!
// Parse the XML
parser = NSXMLParser(contentsOfURL: urlToSend)!
parser.delegate = self
let success:Bool = parser.parse()
if success {
print("parse success!")
print(strXMLData)
dispatch_async(dispatch_get_main_queue(), { () -> Void in
self.lblNameData.text=self.strXMLData
})
} else {
print("parse failure!")
}
}
func parser(parser: NSXMLParser, didStartElement elementName: String, namespaceURI: String?, qualifiedName qName: String?, attributes attributeDict: [String : String]) {
currentElement=elementName;
if(elementName=="quote" || elementName=="author" || elementName=="result")
{
if(elementName=="quote"){
passName=true;
}
passData=true;
}
}
func parser(parser: NSXMLParser, didEndElement elementName: String, namespaceURI: String?, qualifiedName qName: String?) {
currentElement="";
if(elementName=="quote" || elementName=="author" || elementName=="result")
{
if(elementName=="quote"){
passName=false;
}
passData=false;
}
}
func parser(parser: NSXMLParser, foundCharacters string: String) {
if(passName){
strXMLData=strXMLData+"\n\n"+string
}
if(passData)
{
// print(string)
print("work")
}
}
func parser(parser: NSXMLParser, parseErrorOccurred parseError: NSError) {
NSLog("failure error: %#", parseError)
}
}
UPDATE: So I believe I found the error: in my parser function I'm setting strXMLData = strXMLData + "\n\n" + string but after I delete the \n\n I can see that my label updates...why is this?
Alright, so after many instances of trial and error, I think I figured out the answer.
Something was up in my Main.storyboard that didn't like me creating multiple lines in the UILabel, so what I did was click on the label and navigated to the Attributes Inspector. I set the "Lines" parameter to 0 and I was able to see my text!
I would just like to get "first subitem" from the XML document. So far everything works but it always seems to store the last subItem. Basically the program is reading straight through the XML doc and stopping once it finds what I want. Maybe I am not clear on how to stop the parsing after it has found the first item. Do I need to tell the program to stop after it finds the the first item or add them to an array and then pick out a specific part? Any help would be great.
XML Doc
<file>main file
<item>
<subItem>first subitem</subItem>
</item>
</file>
<file>main file
<item>
<subItem>second subitem</subItem>
</item>
</file>
<file>main file
<item>
<subItem>third subitem</subItem>
</item>
</file>
Swift file
class parseThis {
var strXMLData:String = ""
var currentElement:String = ""
var passData:Bool=false
var passName:Bool=false
var itemNeeded = ""
// set up for parsing
func parser(parser: NSXMLParser, didStartElement elementName: String,
namespaceURI: String?, qualifiedName qName: String?,
attributes attributeDict: [String : String]) {
currentElement=elementName;
if(elementName=="file" || elementName=="item" ||
elementName=="subItem")
{
if(elementName=="subItem"){
passName=false;
}
passData=true;
}
}
func parser(parser: NSXMLParser, didEndElement elementName: String,
namespaceURI: String?, qualifiedName qName: String?) {
currentElement="";
currentElement=elementName;
if(elementName=="file" || elementName=="item" ||
elementName=="subItem"){
if(elementName=="subItem"){
passName=false;
}
passData=false;
}
}
func parser(parser: NSXMLParser, foundCharacters string: String) {
if(passName){
strXMLData=strXMLData+"\n\n"+string
}
if(passData)
{
itemNeeded = string
}
A super simplistic way of looking at this is that you only need the didFindCharacters and didEndElement. Every time you get into didFindCharacters you save them to a variable. Then every time you end an element you check whether this is the correct element name and whether it's the first of that element name type. Something like this:
var resultString : String?
var finalResultObject : String?
public func parser(parser: NSXMLParser, didStartElement elementName: String, namespaceURI: String?, qualifiedName qName: String?, attributes attributeDict: [String : String]) {
}
public func parser(parser: NSXMLParser, foundCDATA CDATABlock: NSData)
{
resultString = String(data: CDATABlock, encoding: NSUTF8StringEncoding)
}
public func parser(parser: NSXMLParser, foundCharacters string: String)
{
if(resultString == nil)
{
resultString = ""
}
resultString! += string
}
public func parser(parser: NSXMLParser, didEndElement elementName: String, namespaceURI: String?, qualifiedName qName: String?)
{
if(elementName == "subItem" && finalResultObject == nil)
{
//This is your first element of this type, save whatever you want.
finalResultObject = resultString
}
resultString = nil
}
public func parser(parser: NSXMLParser, parseErrorOccurred parseError: NSError)
{
//Log something in debug if you would like to.
}
I am needing help parsing XML from a URL. I have read on this a lot and cannot figure out how to get this. All the examples I have found are a little ambiguous with the examples and how to grab the info from parsed XML data.
How would I parse this XML
<menu>
<menuitems>
<item price="$10">Pizza</item>
<item price="$5">Salad</item>
<item price="$3">Bread</item>
</menuitems>
</menu>
This is the tutorial I was going off of but I couldn't understand how this tutorial was accessing the data in the arrays and dictionary.
http://www.theappguruz.com/blog/xml-parsing-using-nsxmlparse-swift
In Xcode 7 (Swift 2), how would I parse and access this info. I know this is not how it would be accessed but I am looking for something like the code below.
print ("\(item[0].data)") // Pizza //
print ("\(item[0].price)") // $10 //
Here is the code from the tutorial but I couldn't figure out how to access all the data parsed from the URL. How would I edit this code to fit my structure?
import UIKit
import Foundation
class ViewController: UIViewController, NSXMLParserDelegate
{
var parser = NSXMLParser()
var posts = NSMutableArray()
var elements = NSMutableDictionary()
var element = NSString()
var title1 = NSMutableString()
var date = NSMutableString()
func beginParsing()
{
posts = []
parser = NSXMLParser(contentsOfURL:(NSURL(string:"http://images.apple.com/main/rss/hotnews/hotnews.rss"))!)!
parser.delegate = self
parser.parse()
}
func parser(parser: NSXMLParser, didStartElement elementName: String, namespaceURI: String?, qualifiedName qName: String?, attributes attributeDict: [String : String])
{
element = elementName
if (elementName as NSString).isEqualToString("item")
{
elements = NSMutableDictionary()
elements = [:]
title1 = NSMutableString()
title1 = ""
date = NSMutableString()
date = ""
}
}
func parser(parser: NSXMLParser, foundCharacters string: String)
{
if element.isEqualToString("title") {
title1.appendString(string)
} else if element.isEqualToString("pubDate") {
date.appendString(string)
}
}
func parser(parser: NSXMLParser, didEndElement elementName: String, namespaceURI: String?, qualifiedName qName: String?)
{
if (elementName as NSString).isEqualToString("item") {
if !title1.isEqual(nil) {
elements.setObject(title1, forKey: "title")
}
if !date.isEqual(nil) {
elements.setObject(date, forKey: "date")
}
posts.addObject(elements)
}
}
}
It looks like that parser code was borrowed from something else. If this really is your XML, think it's simpler than that. The only trick in your case is that price is not an element, but rather just an attributeDict of the item element. And I might create my own custom type, Item to capture the name and price of an item.
Anyway, you might end up with something like:
struct Item {
let name: String
let price: String
}
var itemName: String?
var itemPrice: String?
var items: [Item]!
func parserDidStartDocument(parser: NSXMLParser) {
items = []
}
func parser(parser: NSXMLParser, didStartElement elementName: String, namespaceURI: String?, qualifiedName qName: String?, attributes attributeDict: [String : String]) {
if elementName == "item" {
itemPrice = attributeDict["price"]
itemName = ""
}
}
func parser(parser: NSXMLParser, foundCharacters string: String) {
itemName?.appendContentsOf(string)
}
func parser(parser: NSXMLParser, didEndElement elementName: String, namespaceURI: String?, qualifiedName qName: String?) {
if elementName == "item" {
items.append(Item(name: itemName!, price: itemPrice!))
itemName = nil
itemPrice = nil
}
}
When I do that, and print items, I get:
[MyApp.ViewController.Item(name: "Pizza", price: "$10"),
MyApp.ViewController.Item(name: "Salad", price: "$5"),
MyApp.ViewController.Item(name: "Bread", price: "$3")]