合并 angular 中的两个 observable 以将 CSV 转换为 JSON

Merge two observables in angular for CSV to JSON conversion

我有一个 csv 文件,我想将它转换成 JSON

我正在使用 HttpClient 读取 CSV 文件,然后使用 csvToJson 对其进行转换。

此测试代码有效:

this.httpClient
      .get('assets/csv/results.csv', { responseType: 'text' })
      .subscribe(
        (data) => {
          csv()
            .fromString(data)
            .subscribe((jsonObj) => console.log(jsonObj));
        }
      );

但是当我尝试合并这两个 observable 来创建一个函数时:


  convert() {
    this.httpClient
      .get('assets/csv/results.csv', { responseType: 'text' })
      .pipe(switchMap((d) => csv().fromString(d)))
      .subscribe((c) => console.dir(c));
  }

我收到这个错误:

core.js:4352 ERROR TypeError: You provided an invalid object where a stream was expected. You can provide an Observable, Promise, Array, or Iterable.
    at subscribeTo (subscribeTo.js:27)
    at innerSubscribe (innerSubscribe.js:69)
    at SwitchMapSubscriber._innerSub (switchMap.js:44)
    at SwitchMapSubscriber._next (switchMap.js:34)
    at SwitchMapSubscriber.next (Subscriber.js:49)
    at MapSubscriber._next (map.js:35)
    at MapSubscriber.next (Subscriber.js:49)
    at FilterSubscriber._next (filter.js:33)
    at FilterSubscriber.next (Subscriber.js:49)
    at MergeMapSubscriber.notifyNext (mergeMap.js:70)
    at SimpleInnerSubscriber._next (innerSubscribe.js:10)
    at SimpleInnerSubscriber.next (Subscriber.js:49)
    at XMLHttpRequest.onLoad (http.js:1678)
    at ZoneDelegate.invokeTask (zone-evergreen.js:399)
    at Object.onInvokeTask (core.js:27474)
    at ZoneDelegate.invokeTask (zone-evergreen.js:398)

更新

我创建了一个 stackblitz 来进行实验。

在 stackblitz 中我得到一个错误,我没有进入本地主机:

Error in src/app/csv-2-json.service.ts (18:24)
This expression is not callable.
Type '{ default: (param?: Partial<CSVParseParam>, options?: any) => Converter; }' has no call signatures.

在实现 PromiseLike<any[]> 的库 source code I see that the fromString() returns a Converter 中,所以我认为它应该可以工作。

我做错了什么?

错误

如果我们阅读错误消息,则以下部分是必不可少的:您在需要流的位置提供了无效对象

说明

您的代码 return 是 object 在您的 pipe 中的某处,而应该是 observable。我希望这会发生在您的 switchMap 中。我没有使用给定的库,但我希望 csv().fromString(d) 到 return 一个对象而不是一个可观察的对象。

解决方案

如果您通过 of.

object 更改为 observable,我希望您的代码能够正常工作
switchMap(d => of(csv().fromString(d)))

可能更好的解决方案

在我看来,switchMap 在你的案例中是无稽之谈。

1. 如果你想坚持上面的代码,你可以使用 map 代替:

map(d => csv().fromString(d))

2. 如果你想合并所有以前传入的数据,使用scan 来累积所有以前的值。之后您可以对所有以前的数据使用 map

scan((acc, curr) => ([...acc, ...curr]), [])
// I don't know how to accumulate your data as I did not work with the library. I now pushed all the values to an array

我认为问题在于 csvtojson 包。

首先,如果您通过 import * as csv from "csvtojson" 导入它,您在 csv 变量中得到的是一个具有 4 个属性的对象,'csv' 'Converter' 和'default',每一个都指向一个函数。因此,您在 stackblitz 中遇到的错误 Type '{ default: (param?: Partial<CSVParseParam>, options?: any) => Converter; }' has no call signatures. 意味着您正在尝试将对象视为函数并调用它。但是您不能在 Javascript.

中调用对象

您可以通过从 csv' Object, like this const csvFunc = csv["csv"]. Now in csvFunc 中检索 'csv' 函数来向前迈出一步,您有一个函数可以调用。

但此时我们进入另一个问题。如果我们做 const csvInvocationResult = csvFunc().fromString(d) 我们得到的不是标准的 Promise,而是一个接受 then 方法的对象,就像一个普通的 Promise。因此 Object.getPrototypeOf.then(jsonFroCsv => // do something) 实际上有效。

不幸的是,在 Stackbliz 中我无法浏览原型链(我在尝试执行 Object.getPrototypeOf 时遇到错误)所以我不知道这个对象从哪里继承。无论如何,不​​是真正的 Promise,switchMap 运算符不起作用。

我建议你深入研究 csvtojson 库,看看它是如何工作的,看看你是否可以将它调整为 return 一个真正的 Promise 或者找到一种方法来转换它的结果 return真正的承诺。

此回答无法解决您的问题,但我希望对您有所帮助。