2015-07-01 2 views
1

Я новичок в языке Swift, и у меня проблема с разбором XML. Это кажется читаемым, потому что возвращает количество объектов, но оно не печатает значения.NSXMLParserDelegate foundCharacters function return empty

Это XML:

<?xml version="1.0" encoding="utf-8"?> 
<carros> 
    <carro> 
     <nome>Ferrari FF</nome> 
     <desc><![CDATA[A Ferrari FF acaba de ser revelada. Se trata do primeiro modelo da marca a ter tração integral. Além disso, ele conta com um motor dianteiro V12. Se trata de um modelo GT de quatro lugares que não só substitui a 612 mas também atrai um novo tipo de cliente, daquele que gosta de percorrer caminhos mais difíceis que exigem tração integral. Este modelo revolucionário (dentro da marca) tem um novo chassi com entre-eixos maior, além de suspensão independente que incorpora a última geração de amortecedores ajustáveis, além de freios de cerâmica da Brembo. 
    ]]> 
     </desc> 
     <url_info> 
      http://www.ferrari.com/English/GT_Sport%20Cars/CurrentRange/FF/Pages/FF.aspx 
     </url_info> 
     <url_foto> 
      http://www.livroandroid.com.br/livro/carros/esportivos/Ferrari_FF.png 
     </url_foto> 
     <url_video> 
      http://www.livroiphone.com.br/carros/esportivos/ferrari_ff.mp4 
     </url_video> 
     <latitude>44.532218</latitude> 
     <longitude>10.864019</longitude> 
    </carro> 
    <carro> 
     <nome>AUDI GT Spyder</nome> 
     <desc><![CDATA[O mais novo modelo limitado a 333 unidades que vem para preencher a lacuna de modelo top de linha, vaga desde que o cupê do mesmo modelo, há um ano atrás, esgotou todos os pedidos ainda ano passado. 
O segredo do baixo peso é fazer uso de fibra de carbono para boa parte dos painéis de carroceria, e fibra de vidro para os bancos concha. Além disso, o teto da capota é tecido e se retrai em 19 segundos, podendo-se recolhe-lo andando em velocidades de até 50km/h. 
    ]]> 
     </desc> 
     <url_info> 
      http://www.audi.com.br/br/brand/pt.html 
     </url_info> 
     <url_foto> 
      http://www.livroandroid.com.br/livro/carros/esportivos/Audi_Spyder.png 
     </url_foto> 
     <url_video> 
      http://www.livroiphone.com.br/carros/esportivos/audi_gt.mp4 
     </url_video> 
     <latitude>-23.564224</latitude> 
     <longitude>-46.653156</longitude> 
    </carro> 
</carros> 

Это мой NSXMLParser код, все отпечатки в порядке, за исключением tempString печати. Я не уверен, но я думаю, что что-то идет не так в функции foundCharacters.

import Foundation 

class XMLCarroParser: NSObject, NSXMLParserDelegate { 

    var carros: Array<Carro> = [] 
    //variaveis auxiliares para o parser 
    var tempString: String = "" 
    var carro: Carro? 

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

     if(elementName == "carro") { 
      //Tag <carro> encontrada, cria um novo objeto carro 
      carro = Carro() 
      println("creating an object carro") 
     } 

    } 

    func parser(parser: NSXMLParser?!, foundCharacters string: String!) { 
     // Novos caracteres foram encontrados no XML entao cria a string e faz trim 
     tempString += string.stringByTrimmingCharactersInSet(.whitespaceAndNewlineCharacterSet()) 
    } 

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

     if("carros" == elementName) { 
      //Tag de fim </carros> encontrada. Significa que terminou o xml 
      println("destroing the object carro") 
      return 
     } 

     if("carro" == elementName) { 
      //Insere carro no array e limpa o objeto 
      self.carros.append(carro!) 
      carro = nil 
      println("destroing the object carro"); 

      return 
     } 

     /* 
     Se nao é a tag <carro>, pode ser as tags <nome>, <desc>, etc. 
     Copia os valores do XML para o objeto carro 
     Se eistirem tags com o mesmo nome da @property do Carro, o valor sera copiado. 
     */ 
     if(carro != nil) { 
      if("nome" == elementName) { 
       carro!.nome = "nome"; 
       print(" nome ") 
       println(tempString) 
      } else if("desc" == elementName) { 
       carro!.desc = tempString; 
       println(" desc") 
      } else if("url_foto" == elementName) { 
       carro!.url_foto = tempString 
       println(" foto") 
      } else if("url_info" == elementName) { 
       println(" info") 
       carro!.url_info = tempString 
      } else if("url_video" == elementName) { 
       println(" video") 
       carro!.url_video = tempString 
      } else if("latitude" == elementName) { 
       println(" latitude") 
       carro!.latitude = tempString 
      } else if("longitude" == tempString) { 
       println(" longitude") 
       carro!.longitude = tempString 
      } 

      tempString = "" 
     } 
    } 

    func parser(parser: NSXMLParser, parseErrorOccurred parseError: NSError) { 
     NSLog("failure error: %@", parseError) 
    } 


} 
+0

Примечание, в дополнение к вопросам я обратите внимание, если вы сохраните свой текущий 'didEndElement', обратите внимание, что у вас есть пара проблем (например, если' elementName' является 'nomo', вы сохраняете' "nomo" ', а не' tempString', ваш тест для '' longitude '== tempString' должна быть '' longitude' == elementName'). – Rob

ответ

0

Проблема в том, что подпись этого метода неверна. Вероятно, его вообще не называют. Оно должно быть:

func parser(parser: NSXMLParser, foundCharacters string: String?) { 
    tempString += string! 
} 

Обратите внимание, я удалил stringByTrimmingCharactersInSet от foundCharacters. Вы не хотите этого делать, потому что возможно, что для вызова одного строкового значения потребуется несколько вызовов foundCharacters, а чистый эффект обрезки в этой подпрограмме состоит в том, что вы можете обрезать пробелы не только в начале и в конце строки, но также и в середине строки. (Например, если значение элемента было «это тест» и было возвращено в двух вызовах foundCharacters, один раз с «это» и снова с «тестом», если у вас есть foundCharacter триммерные символы, это будет неправильно представлять его как «это isa test».)

Вместо этого сделайте это в didEndElement, где вы сохраните строку.


Кстати, если Carro был ключ-значение кодирования совместимый (легко осуществить, если это NSObject подкласс), код синтаксического анализа упрощается:

class XMLCarroParser: NSObject, NSXMLParserDelegate { 

    var carros = [Carro]() 
    var tempString: String? 
    var carro: Carro? 
    let fields = ["nome", "desc", "url_foto", "url_info", "url_video", "longitude", "latitude"] 

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

     if elementName == "carro" { 
      carro = Carro() 
     } else if contains(fields, elementName) { 
      tempString = "" 
     } 
    } 

    func parser(parser: NSXMLParser, foundCharacters string: String?) { 
     tempString? += string ?? "" 
    } 

    func parser(parser: NSXMLParser, didEndElement elementName: String, namespaceURI: String?, qualifiedName qName: String?) { 
     if elementName == "carro" { 
      self.carros.append(carro!) 
      carro = nil 
     } else if contains(fields, elementName) { 
      carro?.setValue(tempString!.stringByTrimmingCharactersInSet(NSCharacterSet.whitespaceAndNewlineCharacterSet()), forKey: elementName) 
      tempString = nil 
     } 
    } 

    func parser(parser: NSXMLParser, parseErrorOccurred parseError: NSError) { 
     NSLog("failure error: %@", parseError) 
    } 

} 
+0

Он работал частично ... когда я использую carro ?.setValue (tempString! .stringByTrimmingCharactersInSet (NSCharacterSet.whitespaceAndNewlineCharacterSet()), forKey: elementName), он говорит, что у carro нет метода setValue..так я решил использовать все ifs просто проверить ... и это сработало ... есть что-то не так, используя carro ?.setValue? –

+0

@ EricLongo 'Carro' должен быть совместимым с ключом, чтобы это работало. Самый простой способ добиться этого - сделать «Carro» подклассом NSObject. Ясно, что если вы не хотите использовать 'setValue: forKey:', то оставьте свой 'didEndElement' как есть (хотя, очевидно, перемещение обрезки« tempString »там и исправление ошибок« nomo »и« longitude », которые я заметил в моем комментарии к вашему оригинальному вопросу). – Rob

+0

Thats it ... Я сделал Carro подклассом NSObject ... теперь он совершенен. Большое спасибо. –