質問をすることでしか得られない、回答やアドバイスがある。

15分調べてもわからないことは、質問しよう!

新規登録して質問してみよう
ただいま回答率
85.35%
Xcode

Xcodeはソフトウェア開発のための、Appleの統合開発環境です。Mac OSXに付随するかたちで配布されています。

Swift

Swiftは、アップルのiOSおよびOS Xのためのプログラミング言語で、Objective-CやObjective-C++と共存することが意図されています

Q&A

解決済

1回答

537閲覧

特定のキーワードを含む検索結果をRSS表示させたいです。

waiwaina

総合スコア5

Xcode

Xcodeはソフトウェア開発のための、Appleの統合開発環境です。Mac OSXに付随するかたちで配布されています。

Swift

Swiftは、アップルのiOSおよびOS Xのためのプログラミング言語で、Objective-CやObjective-C++と共存することが意図されています

0グッド

0クリップ

投稿2020/02/22 11:51

編集2020/02/25 11:57

swift初学者です。
現在RSSを用いたアプリを作成しています。
特定のキーワードが含まれた内容だけを表示させたいのですが、いろいろ調べてみてもうまくいきません。

どなたかご教授をお願いします。
(検索できるようにではなく、予め設定したワードを含む検索結果を出したいです!)

swift

1import UIKit 2import SegementSlide 3 4class pege1Controller: UITableViewController,SegementSlideContentScrollViewDelegate,XMLParserDelegate { 5 6 var perser = XMLParser() 7 8 var currentElementName:String! 9 10var newsItems = [NewsItems]() 11 override func viewDidLoad() { 12 super.viewDidLoad() 13 14 tableView.backgroundColor = .clear 15 16 let image = UIImage(named: "0") 17 let imageview = UIImageView(frame:CGRect(x: 0, y: 0, width: self.tableView.frame.size.width, height: self.tableView.frame.size.height)) 18 19 imageview.image = image 20 self.tableView.backgroundView = imageview 21 22// XNLパース 23 let urlString = "https://www.lifehacker.jp/feed/index.xml" 24 let url:URL = URL(string:urlString)! 25 perser = XMLParser(contentsOf: url)! 26 perser.delegate = self 27 perser.parse() 28 29 30 } 31 32 @objc var scrollView:UIScrollView{ 33 34 return tableView 35 } 36 37 // MARK: - Table view data source 38 39 override func numberOfSections(in tableView: UITableView) -> Int { 40 // #warning Incomplete implementation, return the number of sections 41 return 1 42 } 43 44 override func tableView(_ tableView: UITableView, numberOfRowsInSection section: Int) -> Int { 45 // #warning Incomplete implementation, return the number of rows 46 return newsItems .count 47 } 48 49 override func tableView(_ tableView: UITableView, heightForRowAt indexPath: IndexPath) -> CGFloat { 50 51 return view.frame.size.height/5 52 } 53 override func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell { 54 let cell = UITableViewCell(style: .subtitle, reuseIdentifier: "Cell") 55 56 cell.backgroundColor = .clear 57 let newsItem = self.newsItems[indexPath.row] 58 59 cell.textLabel?.text = newsItem.title 60 cell.textLabel?.font = UIFont.boldSystemFont(ofSize: 15.0) 61 cell.textLabel?.textColor = .white 62 cell.textLabel?.numberOfLines = 3 63 64 cell.detailTextLabel?.text = newsItem.url 65 cell.detailTextLabel?.textColor = .red 66 67 return cell 68 } 69 70 func parser(_ parser: XMLParser, didStartElement elementName: String, namespaceURI: String?, qualifiedName qName: String?, attributes attributeDict: [String : String] = [:]) { 71 72 currentElementName = nil 73 if elementName == "item"{ 74 75 self.newsItems.append(NewsItems()) 76 77 }else{ 78 79 currentElementName = elementName 80 } 81 } 82 func parser(_ parser: XMLParser, foundCharacters string: String) { 83 84 if self.newsItems.count > 0{ 85 86 let lastItems = self.newsItems[self.newsItems.count - 1] 87 88 89 90 switch self.currentElementName { 91 case "title":lastItems.title = string 92 case "link":lastItems.url = string 93 case "pubDate":lastItems.pubDate = string 94 95 default:break 96 97 98 } 99 } 100 } 101 102 func parser(_ parser: XMLParser, didEndElement elementName: String, namespaceURI: String?, qualifiedName qName: String?) { 103 self .currentElementName = nil } 104 105 func parserDidEndDocument(_ parser: XMLParser) { 106 self .tableView.reloadData() 107 } 108 109 override func tableView(_ tableView: UITableView, didSelectRowAt indexPath: IndexPath) { 110 111 let webviewController = webViewController() 112 webviewController.modalTransitionStyle = .crossDissolve 113 114 let newsItem = newsItems[indexPath.row] 115 UserDefaults.standard.set(newsItem.url, forKey: "url") 116 present(webviewController,animated: true,completion:nil) 117 118 }
import Foundation class NewsItems{ var title:String? var url:String? var pubDate:String? }

気になる質問をクリップする

クリップした質問は、後からいつでもMYページで確認できます。

またクリップした質問に回答があった際、通知やメールを受け取ることができます。

バッドをするには、ログインかつ

こちらの条件を満たす必要があります。

hoshi-takanori

2020/02/25 11:36

差し支えなければ、NewsItems の定義も貼っていただけませんか?
waiwaina

2020/02/25 11:58

ご返信ありがとうございます。 上記のコード下部に記載させていただきました! ご確認お願いします。
guest

回答1

0

ベストアンサー

まず、クラス名の付け方ですが、Swift ではクラスや型の名前は大文字で始めることになってます。ので、pege1Controller は Pege1Controller とすることをお勧めします。また、NewsItems ですが、一つの NewsItems は一つのニュース項目なので、NewsItem と単数形にした方がいいでしょう。変数名の newsItems は配列、つまりニュース項目が複数あるってことなので、こちらは複数形がよいです。

次に、せっかくなので取れる情報は全部取りましょう。ってことで NewsItem を次のようにします。
ちなみに、Swift では description という名前には特別な意味があるので、desc に変更しました。また、pubDate は日付型にしましょう。画像の URL もあるので取っておきます。

swift

1class NewsItem { 2 var title: String? 3 var link: String? 4 var desc: String? 5 var pubDate: Date? 6 var guid: String? 7 var category: String? 8 var imageUrl: String? 9 var creator: String? 10}

さて、XML のパーズを pege1Controller の中でやってますが、これは別に ViewController の中でやつ必要はないので、別のクラスにすると良いでしょう。

swift

1import Foundation 2 3class NewsItemParser: NSObject, XMLParserDelegate { 4 var newsItems = [NewsItem]() 5 var currentItem: NewsItem? 6 var currentElementName: String? 7 8 let dateFormatter: DateFormatter = { 9 let formatter = DateFormatter() 10 formatter.locale = Locale(identifier: "en_US_POSIX") 11 formatter.dateFormat = "EEE, dd MMM yyyy HH:mm:ss Z" 12 return formatter 13 }() 14 15 func parse(url: URL) -> [NewsItem] { 16 let parser = XMLParser(contentsOf: url)! 17 parser.delegate = self 18 parser.parse() 19 return newsItems 20 } 21 22 func parser(_ parser: XMLParser, didStartElement elementName: String, namespaceURI: String?, qualifiedName qName: String?, attributes attributeDict: [String : String] = [:]) { 23 if elementName == "item" { 24 let item = NewsItem() 25 newsItems.append(item) 26 currentItem = item 27 } else { 28 currentElementName = elementName 29 if elementName == "enclosure" { 30 currentItem?.imageUrl = attributeDict["url"] 31 } 32 } 33 } 34 35 func parser(_ parser: XMLParser, foundCharacters string: String) { 36 guard let item = currentItem, let elementName = currentElementName else { return } 37 switch elementName { 38 case "title": 39 item.title = string 40 case "link": 41 item.link = string 42 case "description": 43 item.desc = string 44 case "pubDate": 45 item.pubDate = dateFormatter.date(from: string) 46 case "guid": 47 item.guid = string 48 case "category": 49 item.category = string 50 case "dc:creator": 51 item.creator = string 52 default: 53 break 54 } 55 } 56 57 func parser(_ parser: XMLParser, didEndElement elementName: String, namespaceURI: String?, qualifiedName qName: String?) { 58 if elementName == "item" { 59 currentItem = nil 60 } 61 currentElementName = nil 62 } 63}

そうすると Pege1Controller はこんな感じになるはず。

swift

1class Pege1Controller: UITableViewController,SegementSlideContentScrollViewDelegate { 2 3 var newsItems = [NewsItem]() 4 5 override func viewDidLoad() { 6 super.viewDidLoad() 7 8 // 略 9 10// XNLパース 11 let urlString = "https://www.lifehacker.jp/feed/index.xml" 12 let url:URL = URL(string:urlString)! 13 let parser = NewsItemParser() 14 newsItems = parser.parse(url: url) 15 } 16 17 // 以下略

さて、本題の「特定のキーワードが含まれた内容だけを表示させたい」件ですが、LifeHacker の RSS フィードには特定のキーワードだけの RSS というのはなさそうなので、parser.parse() の結果から特定のキーワードが含まれた内容を検索する必要があります。具体的には、newsItems = parser.parse(url: url) の行を次のように書き換えると良いでしょう。

category が LIFESTYLE であるものだけ表示したい場合

swift

1 let allItems = parser.parse(url: url) 2 3 let category = "LIFESTYLE" 4 for item in allItems { 5 if item.category == category { 6 newsItems.append(item) 7 } 8 } 9 self.tableView.reloadData() 10 11 // または、次のようにも書けます。 12 newsItems = allItems.filter { $0.category == category }

title または desc に「レシピ」を含むものだけ表示したい場合

swift

1 let allItems = parser.parse(url: url) 2 3 let keyword = "レシピ" 4 for item in allItems { 5 if let title = item.title, let desc = item.desc, 6 title.contains(keyword) || desc.contains(keyword) { 7 newsItems.append(item) 8 } 9 } 10 self.tableView.reloadData() 11 12 // または、次のようにも書けます。 13 newsItems = allItems.filter { $0.title?.contains(keyword) == true || $0.desc?.contains(keyword) == true }

title または desc に「仕事」または「ワーク」を含むものだけ表示したい場合

swift

1 let allItems = parser.parse(url: url) 2 3 let keywords = ["仕事", "ワーク"] 4 for item in allItems { 5 if let title = item.title, let desc = item.desc, 6 keywords.contains(where: { title.contains($0) || desc.contains($0) }) { 7 newsItems.append(item) 8 } 9 } 10 self.tableView.reloadData() 11 12 // または、次のようにも書けます。 13 newsItems = allItems.filter { (item) in 14 keywords.contains { item.title?.contains($0) == true || item.desc?.contains($0) == true } 15 }

投稿2020/02/25 14:24

hoshi-takanori

総合スコア7901

バッドをするには、ログインかつ

こちらの条件を満たす必要があります。

waiwaina

2020/02/27 13:00

返信が遅くなり申し訳ありません。 また、ご丁寧にご説明いただき本当にありがとうございます! とてもわかりやすく説明をしてくださり、初心者である私を配慮してくれたおかげもあって、完全にとはまだ言えませんが、理解できたと思います! 今現在は他のエラーが出ており、まだうまく機能するか確認ができていませんが、ここからは自分の力でもなんとかなりそうなので、頑張ってみようと思います。 評価が遅くなることをさけるべく、先にベストアンサーをつけさせていただきます。 ご回答いただき、誠にありがとうございました!
guest

あなたの回答

tips

太字

斜体

打ち消し線

見出し

引用テキストの挿入

コードの挿入

リンクの挿入

リストの挿入

番号リストの挿入

表の挿入

水平線の挿入

プレビュー

15分調べてもわからないことは
teratailで質問しよう!

ただいまの回答率
85.35%

質問をまとめることで
思考を整理して素早く解決

テンプレート機能で
簡単に質問をまとめる

質問する

関連した質問