Talend:将 JSON 行转换为列,从 JSON 中提取列名

Talend : Transform JSON lines to columns, extracting column names from JSON

我有一个 json 休息响应,其结构有点像这样:

{
    "data" : [
        {
            "fields" : [
                { "label" : "John", "value" : "John" },
                { "label" : "Smith", "value" : "/person/4315" },
                { "label" : "43", "value" : "43" },
                { "label" : "London", "value" : "/city/54" }
            ]
        },
        {
            "fields" : [
                { "label" : "Albert", "value" : "Albert" },
                { "label" : "Einstein", "value" : "/person/154" },
                { "label" : "141", "value" : "141" },
                { "label" : "Princeton", "value" : "/city/9541" }
            ]
        }
    ],
    "columns" : ["firstname", "lastname", "age", "city"]
}

我正在寻找一种方法将此数据转换为

这样的行
| first_name_label  | firstname_value | lastname_label | lastname_value | age_label | age_value | city_label | city_value |
---------------------------------------------------------------------------------------------------------------------------
|      John         |   John          | Smith          |  /person/4315  |  43       |    43     |    London  |  /city/54  |
|      Albert       |   Albert        | Einstein       |  /person/154   |  141      |    141    |  Princeton | /city/9541 |

当然,列数和它们的名称可能会改变,所以我不知道运行前的架构。 我可能可以写 java 来处理这个问题,但我想知道是否有更标准的方法。

我是 Talend 的新手,所以我花了几个小时尝试,但由于我的尝试可能完全错误,所以我不会在这里描述它。

感谢您的帮助。

这是我整理的完全动态的解决方案。

首先,您需要阅读 json 以获得列列表。这是 tExtractJSONFields_2 的样子:

然后将列及其位置存储在 tHashOutput 中(您需要在文件 > 项目属性 > 设计器 > 调色板设置中取消隐藏)。在 tMap_2 中,您使用序列获取列的位置:

Numeric.sequence("s", 1, 1) 

这个子作业的输出是:

|=-------+--------=|
|position|column   |
|=-------+--------=|
|1       |firstname|
|2       |lastname |
|3       |age      |
|4       |city     |
'--------+---------'

第二步是再次读取json,以解析字段属性。 与步骤 1 一样,您需要为每个字段添加一个相对于列的位置。这是我用来获取序列的表达式:

(Numeric.sequence("s1", 0, 1) % ((Integer)globalMap.get("tHashOutput_1_NB_LINE"))) + 1 

请注意,我使用了不同的序列名称,因为序列在整个作业中保持其值。我使用 tHashOutput_1 中的列数来保持动态。
这是此子作业的输出:

|=-------+---------+---------------=|
|position|label    |value           |
|=-------+---------+---------------=|
|1       |John     |John            |
|2       |Smith    |/person/4315    |
|3       |43       |43              |
|4       |London   |/city/54        |
|1       |Albert   |Albert          |
|2       |Einstein |/person/154     |
|3       |141      |141             |
|4       |Princeton|/city/9541      |
'--------+---------+----------------'

在最后一个子作业中,您需要使用我们存储的列位置将字段数据与列连接起来。

在 tSplitRow_1 中,我为每个传入行生成 2 行。每行都是一个键值对。第一行是 <columnName>_label(如 firstname_label、lastname_label),它的值是来自字段的标签。第 2 行的键是 <columnName>_value,它的值是来自字段的值。

再次,我们需要在 tMap_4 中添加一个位置到我们的数据中,使用这个表达式:

(Numeric.sequence("s2", 0, 1) / ((Integer)globalMap.get("tHashOutput_1_NB_LINE") * 2)) + 1

请注意,由于 tSplitRow 中的行数是原来的两倍,因此我将列数乘以 2。
这将为需要位于输出文件中同一行的数据分配相同的 ID。 此 tMap 的输出将类似于:

|=-+---------------+-----------=|
|id|col_label      |col_value   |
|=-+---------------+-----------=|
|1 |firstname_label|John        |
|1 |firstname_value|John        |
|1 |lastname_label |Smith       |
|1 |lastname_value |/person/4315|
|1 |age_label      |43          |
|1 |age_value      |43          |
|1 |city_label     |London      |
|1 |city_value     |/city/54    |
|2 |firstname_label|Albert      |
|2 |firstname_value|Albert      |
|2 |lastname_label |Einstein    |
|2 |lastname_value |/person/154 |
|2 |age_label      |141         |
|2 |age_value      |141         |
|2 |city_label     |Princeton   |
|2 |city_value     |/city/9541  |
'--+---------------+------------'

这将我们带到最后一个组件 tPivotToColumnsDelimited,它将使用唯一 ID 将我们的行转换为列。

最终结果是一个 csv 文件,如:

id;firstname_label;firstname_value;lastname_label;lastname_value;age_label;age_value;city_label;city_value
1;John;John;Smith;/person/4315;43;43;London;/city/54
2;Albert;Albert;Einstein;/person/154;141;141;Princeton;/city/9541

请注意,您最终在开头有一个无关的列,它是行 ID,可以通过读取文件并删除它来轻松删除它。
我尝试在输入 json 中添加一个新列以及相应的字段,它按预期工作。