2017-01-09 4 views
0

Я загрузил библиотеку xml2json из npm, а затем установил typings, но все же я получаю что-то не так с кодом, я вижу, что данные был разобран в консоли, но он не отображается в ion-list.Как разобрать rss-канал в формате xml вместо json-формата из url - Ionic 2

rss-service.ts

import { Injectable } from '@angular/core'; 
import { Http } from '@angular/http'; 
import 'rxjs/add/operator/map'; 
import {Observable} from 'rxjs/Observable'; 
import * as x2js from 'xml2json'; 

@Injectable() 
export class RssService { 

    public xml2js: any = []; 

    constructor(public http: Http) { 
    console.log('Hello RssService Provider'); 
    } 

    load() { 

     return Observable.create(s => { 
      this.http.get('url.xml') 
      .map(res => res.text()) 
      .subscribe(data => { 
      var posts = JSON.stringify(data); 
      x2js.parseString(posts, function (err, result) { 
       console.log(posts); 
      }); 
      }, error => { 
       console.log(JSON.stringify(error)); 
       }); 
      }); 
    } 
} 

home.ts - home.html

import { NavController } from 'ionic-angular'; 
import { Component } from '@angular/core'; 
import { RssService } from '../../providers/rss-service/rss-service'; 
import { DetailPage } from '../detail-page/detail-page'; 

@Component({ 
    selector: 'page-home', 
    templateUrl: 'home.html', 
    providers: [RssService] 
}) 
export class HomePage { 

    doRefresh(refresher) { 
    console.log('Begin async operation', refresher); 

    setTimeout(() => { 
     console.log('Async operation has ended'); 
     refresher.complete(); 
    }, 2000); 
    } 

    public entries: any = []; 

    constructor(public rssService:RssService, public nav:NavController) {  
    } 

    ionViewDidLoad(){ 
     this.rssService.load().subscribe(
      data => { 
       this.entries.push(data); 
      } 
    ); 
    } 

    openPage(entry) { 
     console.log('open page called with ' + entry.title); 
     this.nav.push(DetailPage, {selectedEntry:entry}); 
    } 

} 

<ion-header> 
    <ion-navbar color="primary"> 
    <ion-title text-center> 
     App Name 
    </ion-title> 
    </ion-navbar> 
</ion-header> 

<ion-content padding> 
    <ion-refresher (ionRefresh)="doRefresh($event)"> 
    <ion-refresher-content></ion-refresher-content> 
    </ion-refresher> 
    <ion-list> 
     <ion-item *ngFor="let entry of entries" (click)="openPage(entry)" text-wrap> 
      <h2 class="feed-title">{{entry.title}}</h2> 
     </ion-item> 
    </ion-list> 
</ion-content> 

Редактировать

Я также попытался с помощью DOMParser и я в состоянии отобразить в консоли массив <item> где каждый из них содержит <title>, <description>, <pubDate>, <enclosure>, <link>, но не могут отображать их в ion-list.

Не могли бы вы мне помочь?

load() { 

return Observable.create(s => { 
    this.http.get('url.xml') 
    .map(res => res.text()) 
    .subscribe(data => { 
    if(data) { 
     var parser = new DOMParser(); 
     var xmlData = parser.parseFromString(data, "application/xml"); 
     var items = xmlData.querySelectorAll("item"); 
     for (var index = 0; index < items.length; index++) { 
     var element = items[index]; 
     console.log(element); 
     } 
    } 
    }); 
}); 

Это XML Я пытаюсь разобрать

<?xml version="1.0" encoding="utf-8"?> 
<rss xmlns:content="http://purl.org/rss/1.0/modules/content/" version="2.0"> 
    <channel> 
    <title><![CDATA[Site Name Home]]></title> 
    <link>http://www.my-site.it/home</link> 
    <description><![CDATA[Site description]]></description> 
    <pubDate>Sat, 14 Jan 2017 11:36:51 +0100</pubDate> 
    <image> 
     <url>http://www.image.it/uploads/../images/rss.jpg</url> 
     <title><![CDATA[Site Name]]></title> 
     <link>http://www.sitename.it/home</link> 
    </image> 
    <generator>Zend_Feed</generator> 
    <language>en</language> 
    <docs>http://blogs.law.harvard.edu/tech/rss</docs> 
    <item> 
     <title><![CDATA[Title]]></title> 
     <link>http://link</link> 
     <description><![CDATA[Description]]></description> 
     <pubDate>Sat, 14 Jan 2017 10:28:00 +0100</pubDate> 
     <enclosure url="http://image-url.jpg" type="image/jpeg" length="110"/> 
    </item> 
    . 
    . 
    <item>...</item> 

в консоли я получаю именно массив элемента, показанного выше

<item> 
    <title><![CDATA[Title]]></title> 
    <link>http://link</link> 
    <description><![CDATA[Description]]></description> 
    <pubDate>Sat, 14 Jan 2017 10:28:00 +0100</pubDate> 
    <enclosure url="http://image-url.jpg" type="image/jpeg" length="110"/> 
</item> 
. 
. 
<item>...</item> 

Edit 2

Добавил свой код в load()

load() { 
    return Observable.create(s => { 
    this.http.get('url.xml') 
    .map(res => res.text()) 
    .subscribe(data => { 
     var parser = new DOMParser(); 
     var xmlData = parser.parseFromString(data, "application/xml"); 

     // First get the information (title, description, ...) 
     var info = {}; 
     (xmlData.querySelectorAll("channel>*:not(item)") || []).forEach(function(e){ 
     var infoData = {}; 
     var found = false; 
     e.childNodes.forEach(function(e){ 
      // skip text nodes 
      if(e.nodeType == 3) return; 
      found = true; 
      infoData[e.tagName] = e.textContent; 
     }); 
     if(found) info[e.tagName] = infoData; 
     else info[e.tagName] = e.textContent; 
     }); 

     // Then, get the list of items 
     var items = []; 
     (xmlData.querySelectorAll("channel>item") || []).forEach(function(item){ 
     var itemData = {}; 
     item.childNodes.forEach(function(e){ 
      // skip over text nodes 
      if(e.nodeType == 3) return; 

      // get attributes if exist (to support the 'enclosure' element) 
      var attr = {}; 
      var found = false; 
      for(var i = 0, atr = e.attributes, l = e.attributes.length; i < l; i++){ 
      found = true; 
      attr[atr[i].name] = atr[i].value; 
      } 
      if(found) itemData[e.tagName] = attr; 
      else itemData[e.tagName] = e.textContent; 
     }); 
     items.push(itemData); 
     }); 
     console.log("INFO: ", info); 
     console.log("ITEMS: ", items); 
    }); 
    }); 
} 
+0

Если вы пишете код для браузера, вы можете попробовать DOMParser https://developer.mozilla.org/en/docs/Web/API/DOMParser –

+0

Я прочитал статью, но как ее реализовать с помощью моего кода? – Rick

+0

'DOMParser' только анализирует XML в дерево, которое вы управляете как' document' с 'getElementById',' appendChild' и т. Д. Вам нужно извлечь информацию вручную, чтобы вам нужно было знать формат RSS (что довольно просто). Например, получите заголовок с именем tree.querySelector («title»). InnerText'. –

ответ

1

Этот код будет генерировать два объекта: info который содержит информацию, например, название, описание ..., и items, который представляет собой массив объекта, представляющий элементы.

Имена свойств этих объектов являются либо именами тегов, либо именами атрибутов, и они следуют за той же иерархией, что и данные XML. Теперь, так как они являются объектами, это будет легко получить доступ к данным, например:

// Info object 
var title = info.title; 
var imgUrl = info.image.url; 
//... 

// Items array 
items.forEach(function(item){ 
    var itemTitle = item.title; 
    var itemEnclosureUrl = item.enclosure.url; 
    //... 
}); 

var data = '<rss xmlns:content="http://purl.org/rss/1.0/modules/content/" version="2.0"><channel><title>Site Name</title><link>http://www.my-site.it/home</link><description>Site description</description><pubDate>Sat, 14 Jan 2017 11:36:51 +0100</pubDate><image><url>http://www.image.it/uploads/../images/rss.jpg</url><title><![CDATA[Site Name]]></title><link>http://www.sitename.it/home</link></image><generator>Zend_Feed</generator><language>en</language><docs>http://blogs.law.harvard.edu/tech/rss</docs><item><title><![CDATA[Title]]></title><link>http://link</link><description>Description</description><pubDate>Sat, 14 Jan 2017 10:28:00 +0100</pubDate><enclosure url="http://image-url.jpg" type="image/jpeg" length="110"/></item></channel></rss>'; 
 

 

 
var parser = new DOMParser(); 
 
var xmlData = parser.parseFromString(data, "application/xml"); 
 

 
// First get the information (title, description, ...) 
 
var info = {}; 
 
(xmlData.querySelectorAll("channel>*:not(item)") || []).forEach(function(e){ 
 
    var infoData = {}; 
 
    var found = false; 
 
    e.childNodes.forEach(function(e){ 
 
     // skip text nodes 
 
     if(e.nodeType == 3) return; 
 
     found = true; 
 
     infoData[e.tagName] = e.textContent; 
 
    }); 
 
    if(found) info[e.tagName] = infoData; 
 
    else info[e.tagName] = e.textContent; 
 
}); 
 

 
// Then, get the list of items 
 
var items = []; 
 
(xmlData.querySelectorAll("channel>item") || []).forEach(function(item){ 
 
    var itemData = {}; 
 
    item.childNodes.forEach(function(e){ 
 
     // skip over text nodes 
 
     if(e.nodeType == 3) return; 
 

 
     // get attributes if exist (to support the 'enclosure' element) 
 
     var attr = {}; 
 
     var found = false; 
 
     for(var i = 0, atr = e.attributes, l = e.attributes.length; i < l; i++){ 
 
      found = true; 
 
      attr[atr[i].name] = atr[i].value; 
 
     } 
 
     if(found) itemData[e.tagName] = attr; 
 
     else itemData[e.tagName] = e.textContent; 
 
    }); 
 
    items.push(itemData); 
 
}); 
 

 
console.log("INFO: ", info); 
 
console.log("ITEMS: ", items);

Это будет работать хорошо, если данные XML был в форме предоставленной вами. Если он изменен, часть кода необходимо изменить, чтобы адаптироваться к новому формату.

Этот код был основан на предположении, что в XML-данных содержится один элемент и что заголовок и описание, где не теги, как вы указали (я предполагал, что заголовок и описание будут текстовыми, а не тегами).

+0

Есть некоторые вещи, которые я не понимаю: 1. Вы использовали 'var data = '...'' как нечто, что не изменится, поскольку я понимаю, но мне нужно получить rss-канал с URL-адреса, который обновляет его содержимое 2. Должен ли код выше быть в функции 'load()'? Нет ли каких-либо изменений в коде в 'home.ts'? Потому что, насколько я понял, проблема заключалась в том, чтобы не анализировать данные с Url, а отображать их в «ion-list», поэтому я предположил, что в 'home.ts' было что-то не так: – Rick

+0

1)' var data =. ..' был только для того, чтобы просто получить действительный фрагмент кода, в вашем коде вы получаете 'data', используя' this.http.get ('url.xml') ... ', поэтому данные не будут фиксированной строкой. 2) вы можете добавить этот код для загрузки или его можно поместить в другую функцию ('function parseData (data) {...', которые берут 'data' (xml string) в качестве аргумента, а затем анализируют его на' info' и 'items', которые вы затем будете использовать для создания своего« ионного списка »легко (используя' document.createElement (...) ',' .... appendChild (...) '' .... textContent = ... '); –

+0

Я получаю ошибку _Typescript Свойство 'forEach' не существует в типе 'NodeListOf | undefined []' ._ в этих строках' (xmlData.querySelectorAll ("channel> *: not (item) ") || []). forEach (function (e) { var infoData = {};' и '(xmlData.querySelectorAll (" channel> item ") || []). forEach (function (item) {'. Я добавил ваш код внутри функции' load() ', как вы можете видеть выше. – Rick