Home > Mobile >  Compose object from nested list
Compose object from nested list

Time:12-14

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.

  • Related