I have a generic json generated from an XML.
{
"contextInfoDTOList": [
{
"key": "context_info",
"list": [
{
"key": "composition",
"list": [
{
"key": "parts",
"list": [
{
"key": "part",
"list": [
{
"list": [
{
"key": "materials",
"list": [
{
"key": "material",
"list": [
{
"key": "material_value",
"value": "100"
},
{
"key": "material_name",
"value": "polyester"
}
]
}
]
},
{
"key": "part_name",
"value": "LINING"
}
]
},
{
"list": [
{
"key": "materials",
"list": [
{
"key": "material",
"list": [
{
"key": "material_value",
"value": "100"
},
{
"key": "material_name",
"value": "cow leather"
}
]
}
]
},
{
"key": "part_name",
"value": "OUTER SHELL"
}
]
}
]
}
]
}
]
},
{
"key": "explanation"
}
]
}
]
}
I need to extract the information to something like this:
COMPOSITION
Lining
100 % polyester
Outer Shell
100 % cow leather
I have tried a forEach approach, acceding to the keys (composition, parts, materials...), but it gets so dirty and I cannot get the materials list.
I'm considering about using a reduce to obtain an object, but I don't know how to pass an object and use recursivity through the nested list.
Desired object:
export class ContextInfo {
composition: Composition;
explanation: string;
}
export class Composition {
parts: Part[] = [];
}
export class Part {
partName: string;
materials: Material[] = [];
}
export class Material {
name: string;
value: number;
}
Any help would be appreciated. Thanks in advance!
CodePudding user response:
Now it's your responsibility, to work with the data...
let contextInfoDTOList = [{ key: "context_info", list: [{ key: "composition", list: [{ key: "parts", list: [{ key: "part", list: [{ list: [{ key: "materials", list: [{ key: "material", list: [{ key: "material_value", value: "100" }, { key: "material_name", value: "polyester" }] }] }, { key: "part_name", value: "LINING" }] }, { list: [{ key: "materials", list: [{ key: "material", list: [{ key: "material_value", value: "100" }, { key: "material_name", value: "cow leather" }] }] }, { key: "part_name", value: "OUTER SHELL" }] }] }] }] }, { key: "explanation" }] }]
function* getAllKeyValue(list = [], path = []) {
for (let item of list)
if ("value" in item)
yield [item, path]
else
yield* getAllKeyValue(item.list, path.concat(item.key))
}
for (let [item, _path] of getAllKeyValue(contextInfoDTOList)) {
console.log(item);
// Todo: work with the data
}
CodePudding user response:
That's a pretty ugly input format you have. But by continually filtering and finding nodes, we can build your output in a fairly reasonable manner:
const byKey = (target) => ({key}) => key == target
const extract = (res) => res .contextInfoDTOList .filter (byKey ('context_info')) .map (info => ({
explanation: info .list .find (byKey ('explanation')) .value,
composition: info .list .find (byKey ('composition')) .list .filter (byKey ('parts')) .map (parts => ({
parts: parts .list .filter (byKey ('part')) .flatMap (p => p.list .map (q => q.list)) .map (part => ({
partName: part .find (byKey ('part_name')) .value,
material: part .find (byKey ('materials')) .list .map (material => ({
name: material .list .find (byKey ('material_name')) .value,
value: material .list .find (byKey ('material_value')) .value
}))
}))
}))
}))
const res = {contextInfoDTOList: [{key: "context_info", list: [{key: "composition", list: [{key: "parts", list: [{key: "part", list: [{list: [{key: "materials", list: [{key: "material", list: [{key: "material_value", value: "100"}, {key: "material_name", value: "polyester"}]}]}, {key: "part_name", value: "LINING"}]}, {list: [{key: "materials", list: [{key: "material", list: [{key: "material_value", value: "100"}, {key: "material_name", value: "cow leather"}]}]}, {key: "part_name", value: "OUTER SHELL"}]}]}]}]}, {key: "explanation", value: "foobar"}]}]}
console .log (extract (res))
.as-console-wrapper {max-height: 100% !important; top: 0}
(Note that I had to add a dummy "value"
to your "explanation"
node to get it to extract properly. If we don't do this, we'd get an undefined
explanation.)
We use the helper byKey
simply to reduce the noise in the body of the function.