2015-10-15 33 views
0

我想解析Swift中的XML文件,並且在理解NSMutableDictionary如何在存儲數值的過程中遇到一些麻煩元素。解析Swift中的XML文件(Xcode v 7.0.1)並從字典中檢索值

的XML文件看起來像這樣,

<coord2 count="6"> 
    <markers> 
    <marker> 
     <lat>36.99058167</lat> 
     <lng>-122.06620333</lng> 
     <timestamp>1444931620</timestamp> 
     <route>LOOP</route> 
     <id>7855</id> 
     <predictions> 
     ,4,5,,6,7,,,,10,,,11,,11,,13,15,,14,,,16,,,0,,,2,,,,,,,,,,,,,, 
     </predictions> 
     <update_seconds>10</update_seconds> 
     <index>4</index> 
    </marker> 
    <marker> 
     <lat>36.99296</lat> 
     <lng>-122.06517333</lng> 
     <timestamp>1444934786</timestamp> 
     <route>UPPER CAMPUS</route> 
     <id>7860</id> 
     <predictions> 
     15,,,14,,,13,12,11,,10,9,,8,,7,,,6,,5,4,,3,2,,1,0,,,,,,,,,,,,,,, 
     </predictions> 
     <update_seconds>10</update_seconds> 
     <index>4</index> 
    </marker> 
    </markers> 
    <curr_time>1444931622</curr_time> 
</coord2> 

我試圖解析XML文件的方法是使用下面的代碼,我從一個教程發現在 http://www.theappguruz.com/blog/xml-parsing-using-nsxmlparse-swift

import UIKit 
import GoogleMaps 

class ViewController: UIViewController, NSXMLParserDelegate { 

    var parser = NSXMLParser() 
    var posts = NSMutableArray() 
    var elements = NSMutableDictionary() 
    var element = NSString() 
    var route = NSMutableString() 
    var timestamp = NSMutableString() 

    func beginParsing() 
    { 
     posts = [] 
     parser = NSXMLParser(contentsOfURL:(NSURL(string:"http://xmfile.xml"))!)! 
     parser.delegate = self 
     parser.parse() 
    } 

    override func viewDidLoad() { 
     super.viewDidLoad() 
     beginParsing() 

     print("The route is") 
     let t = elements["route"]! 
     print(t) 
     print("The timestamp is") 
     let u = elements["timestamp"]! 
     print(u) 
    } 

    override func didReceiveMemoryWarning() { 
     super.didReceiveMemoryWarning() 
     // Dispose of any resources that can be recreated. 
    } 

    // didStartElement 
    func parser(parser: NSXMLParser, didStartElement elementName: String, namespaceURI: String?, qualifiedName qName: String?, attributes attributeDict: [String : String]) 
    { 
     element = elementName 
     if (elementName as NSString).isEqualToString("marker") 
     { 
      elements = NSMutableDictionary() 
      elements = [:] 
      route = NSMutableString() 
      route = "" 
      timestamp = NSMutableString() 
      timestamp = "" 
     } 
    } 

    // foundCharacters 
    func parser(parser: NSXMLParser, foundCharacters string: String) 
    { 
     if element.isEqualToString("route") { 
      route.appendString(string) 
     } else if element.isEqualToString("timestamp") { 
      timestamp.appendString(string) 
     } 
    } 

    // didEndElement 
    func parser(parser: NSXMLParser, didEndElement elementName: String, namespaceURI: String?, qualifiedName qName: String?) 
    { 
     if (elementName as NSString).isEqualToString("marker") { 
      if !route.isEqual(nil) { 
       elements.setObject(route, forKey: "route") 
      } 
      if !timestamp.isEqual(nil) { 
       elements.setObject(timestamp, forKey: "timestamp") 
      } 
      posts.addObject(elements) 
     } 
    } 

} 

現在我只關注「路由」和「時間戳」元素,以便了解分析的工作原理。輸出我得到的,當我

let t = elements["route"]! 
print(t) 
print("previous is route") 
let u = elements["timestamp"]! 
print(u) 
print("previous is timestamp") 

始終是在XML文件中的名稱最後元素的值。所以,對於我提供的6行的代碼的輸出處的示例XML文件上面會

路線是
UPPER校園

該時間戳爲

我希望能夠區分多個「」標記「elem瀏覽XML文件並檢索標記內元素的值。換句話說,能夠獲得第一個標記內元素的值,而不僅僅是最後一個。我會如何去做這件事?

+0

你是否需要使用NSMutableDictionary/NSMutableArray或創建類來表示Coord2/Marker是一個選項?我想問的原因是,如果你可以使用自定義類,你可以使用另一種方法來乾淨地解析你的XML,並有更多可管理的代碼... – Benzi

+0

感謝您的迴應。現在,我接受建議。我對Swift很陌生,所以我在學習。我如何用自定義類來完成這個任務? – Ivan

+0

好的...我已經爲你提供了一個答案;請在下面查看。 – Benzi

回答

4

注意 我已經把whole thing in a gist您可以複製並粘貼到一個遊樂場。


讓我們來看一個簡單的例子來獲得一個開始:

let xml = "<coord2 count=\"3\">" 
+ "<markers>" 
    + "<marker>" 
    + "<item>marker1</item>" 
    + "</marker>" 
    + "<marker>" 
    + "<item>marker2</item>" 
    + "<lat>36</lat>" 
    + "</marker>" 
+ "</markers>" 
+ "</coord2>" 

有點收窄,但標記可以有一個項目名稱(字符串)和LAT值(INT)。一個Coord2將有一個標記數組和一個count(int)屬性。

要使用自定義類來解析上述問題,下面介紹一種方法。

首先創建一個ParserBase類,爲我們做一些基礎工作,即積累foundCharacters,以便它可以很容易地被子類使用。 此外(更重要的)它有一個parent屬性,用於保存對父容器類的引用[這用於我們將解析XML的方式]。

// Simple base class that is used to consume foundCharacters 
// via the parser 

class ParserBase : NSObject, NSXMLParserDelegate { 

    var currentElement:String = "" 
    var foundCharacters = "" 
    weak var parent:ParserBase? = nil 

    func parser(parser: NSXMLParser, didStartElement elementName: String, namespaceURI: String?, qualifiedName qName: String?, attributes attributeDict: [String : String]) { 

     currentElement = elementName 
    } 

    func parser(parser: NSXMLParser, foundCharacters string: String) { 
     self.foundCharacters += string 
    } 

} 

由於coord2是我們的根標籤,我們將創建一個類,將映射到該標籤 - 它代表根對象,有標記,計數屬性的數組,也是根代表XMLParser的對象。

// Represents a coord2 tag 
// It has a count attribute 
// and a collection of markers 

class Coord2 : ParserBase { 


    var count = 0 
    var markers = [Marker]() 



    override func parser(parser: NSXMLParser, didStartElement elementName: String, namespaceURI: String?, qualifiedName qName: String?, attributes attributeDict: [String : String]) { 

     print("processing <\(elementName)> tag from Coord") 

     if elementName == "coord2" { 

      // if we are processing a coord2 tag, we are at the root 
      // of this example 
      // extract the count value and set it 
      if let c = Int(attributeDict["count"]!) { 
       self.count = c 
      } 
     } 

     // if we found a marker tag, delegate further responsibility 
     // to parsing to a new instance of Marker 

     if elementName == "marker" { 
      let marker = Marker() 
      self.markers.append(marker) 

      // push responsibility 
      parser.delegate = marker 

      // let marker know who we are 
      // so that once marker is done XML processing 
      // it can return parsing responsibility back 
      marker.parent = self 
     } 
    } 


} 

標記類如下:

class Marker : ParserBase { 

    var item = "" 
    var lat = 0 

    func parser(parser: NSXMLParser, didEndElement elementName: String, namespaceURI: String?, qualifiedName qName: String?) { 

     print("processing <\(elementName)> tag from Marker") 

     // if we finished an item tag, the ParserBase parent 
     // would have accumulated the found characters 
     // so just assign that to our item variable 
     if elementName == "item" { 
      self.item = foundCharacters 
     } 

      // similarly for lat tags 
      // convert the lat to an int for example 
     else if elementName == "lat" { 
      if let l = Int(foundCharacters) { 
       self.lat = l 
      } 
     } 

     // if we reached the </marker> tag, we do not 
     // have anything further to do, so delegate 
     // parsing responsibility to parent 
     else if elementName == "marker" { 
      parser.delegate = self.parent 
     } 

     // reset found characters 
     foundCharacters = "" 
    } 

} 

現在上分析,提取信息,並打印的東西。

let xmlData = xml.dataUsingEncoding(NSUTF8StringEncoding)! 
let parser = NSXMLParser(data: xmlData) 

let coord = Coord2() 
parser.delegate = coord 

parser.parse() 


print("coord has a count attribute of \(coord.count)") 
print("coord has \(coord.markers.count) markers") 

for marker in coord.markers { 
    print("marker item = \(marker.item) and lat = \(marker.lat)") 
} 

,其輸出如下:

coord has a count attribute of 3 
coord has 2 markers 
marker item = marker1 and lat = 0 
marker item = marker2 and lat = 36 
+0

哇,非常感謝你的幫助@Benzi。還有一個問題。我在哪裏放置XML文件的URL?我的機器上本地沒有XML文件。另外,我把最後一塊代碼放在我的'override func viewDidLoad(){..}'函數中嗎? – Ivan

+0

是的,你可以把最後一塊代碼放在'viewDidLoad'中......至於URL,你到目前爲止如何使用解析器?如果你已經用類似parser = NSXMLParser(contentsOfURL:(NSURL(string:「http://xmfile.xml」))!)!'的方式構建它,那麼就用它來代替最後一行的相應行塊。 (我使用的是Playground,所以不得不將XML放在一個字符串中。) – Benzi

+0

太棒了。大多數情況下,除了將字符串轉換爲Double以外,其他所有工作都正常。我在你的回覆中看到你將它投射到一個Int。我需要投到Double,但它不工作。我試着'var lat =「」','var lati = 0.0','self.lat = foundCharacters','self.lati =(self.lat as NSString).doubleValue'。 'self.lat'的值是「36.97728」,但'self.lati'將保持爲0.0 – Ivan

4

我已經使用Class下創建以獲得字典從XML數據。

https://github.com/Bhaavik/BDXmlParser

您需要添加類並調用下面函數字典響應

讓objXmlParser = BbXmlParser() 讓dictResponse = objXmlParser.getdictionaryFromXmlData(數據!) 打印(dictResponse) 在這裏,你用字典去。 :)

+0

如果一個問題是另一個問題的重複,**標記**問題是重複的而不是回答。無論如何不要多次發佈相同的答案。謝謝! – Moritz

+0

感謝您的建議!這是我的第一個答案,我正在學習東西:) – Bhavik

+0

然後,您應該閱讀[參考]並查看[幫助]中的各種文章。它會幫助你做出更好的答案(我的意思是,遵循網站指南的答案)。 :) – Moritz

1

在雨燕2.2:

假設你的XML文件位於你的個人電腦上任何地方,讓XML文件:

<!DOCTYPE suite SYSTEM "http://.dtd" > 

<packages> 
    <package name="packageone" /> 
</packages> 

<test name="testOne"> 
    <classes> 
     <class name="TestClassOne"> 
      <methods> 
       <include name="test_480" /> 
       <include name="test_481" /> 
       <include name="test_482" /> 
      </methods> 
     </class> 
    </classes> 
</test> 
<test name="testOne"> 
    <classes> 
     <class name="TestClassOne"> 
      <methods> 
       <include name="test_111" /> 
       <include name="test_112" /> 
       <include name="test_113" /> 
      </methods> 
     </class> 
    </classes> 
</test> 

所以,如果你wa NT從這個XML只讀測試用例名稱,使用下面的代碼:

import Foundation 

class XmlParsing : NSObject, NSXMLParserDelegate { 

var element:String = "default" 
var testCaseName = [String]() 

func parser(parser: NSXMLParser, didStartElement elementName: String, namespaceURI: String?, qualifiedName qName: String?, attributes attributeDict: [String : String]) { 

    if(elementName == "include"){ 

     //you can store the data in an array or any other way, if you want to use it in anywhere. 
     //testCaseName.append(attributeDict["name"]!) // this is used to store the test cases name 
     print(attributeDict["name"]!) 
    } 
    }  

} 

現在調用的功能等:

let path = NSURL(fileURLWithPath: "xml-file-location").URLByAppendingPathComponent("test.xml") 

var fileContent = try NSString(contentsOfURL: path, encoding: NSUTF8StringEncoding) as String 

let data = fileContent.dataUsingEncoding(NSUTF8StringEncoding) //convert string to data for xml parsing 

let xmlParser = NSXMLParser(data: data!) //create xml parser 

let xmlRead = XmlParsing() // create the object of that class where function is declared. 

xmlParser.delegate = xmlRead //use that object to delegate 
xmlParser.parse() // parse the xml 

xmlParser.parse() 

被調用,比解析器功能被稱爲並執行必要的工作。輸出是:

test_480 
test_481 
test_482 
test_111 
test_112 
test_113 

另一個重要的是解析器有重載函數。你可以使用它們作爲你的要求。

例如,如果您需要從XML文件中讀取任何

commented node 

,請使用XmlParsing類下面的解析器功能:

func parser(parser: NSXMLParser, foundComment comment: String) { 

    print(comment) 
} 

這是找到API鏈接查看詳情:https://developer.apple.com/library/ios/documentation/Cocoa/Reference/NSXMLParserDelegate_Protocol/#//apple_ref/occ/intfm/NSXMLParserDelegate/parser:foundComment