denkan / cheerio-json-mapper

MIT License
18 stars 4 forks source link

Dynamic keys #2

Open Roosteridk opened 1 year ago

Roosteridk commented 1 year ago

Is it possible to to do something like

const html= `
  <table>
    <tr>
      <th>Name</th>
      <th>Age</th>
    </tr>
    <tr>
      <td>John</td>
      <td>30</td>
    </tr>
    <tr>
      <td>Jane</td>
      <td>28</td>
    </tr>
  </table>
`;

const schema = [
  {
    "th: "td"
  }
]

which would map to:

[
  {
    "Name": "John",
    "Age": "30"
  },
  {
    "Name": "James",
    "Age": "28"
  },
]
denkan commented 1 year ago

Hi, nice idea - I think we could look into this, for sure.

But if you're in a hurry, you could solve this with custom pipes. Meaning, create one initial structure and transform it to what you need with a pipe function, e.g:

const schema = {
 rows: [
    {
      $: 'tr',
      cols: [
        {
          $: 'th,td',
          val: '$'
        }
      ]
    }
  ]
};

Initial output:

{
  "rows": [
    {
      "cols": [
        { "val": "Name" },
        { "val": "Age" }
      ]
    },
    {
      "cols": [
        { "val": "John" },
        { "val": "30" }
      ]
    },
    {
      "cols": [
        { "val": "Jane" },
        { "val": "28" }
      ]
    }
  ]  
}

Adding a custom pipe to transform data into desired result:

const pipeFns = {
  /** Transform root object into desired list structure */
  transformTable: ({ value }) => {
    // `value` = root object
    const resultList = [];
    const headers = value.rows[0].cols.map((h) => h.val); // e.g ["Name", "Age"]
    const rows = value.rows.slice(1); // skip header row
    for (const row of rows) {
      const resultItem = {};
      headers.forEach((h, i) => (resultItem[h] = row.cols[i].val));
      resultList.push(resultItem);
    }
    return resultList;
  },
};

const schema = {
  rows: [
    {
      $: 'tr',
      cols: [
        {
          $: 'th,td',
          val: '$'
        }
      ]
    }
  ],
  '|': 'transformTable' // run custom pipe to root object
};

const result = await cheerioJsonMapper(html, schema, { pipeFns });

It sure is more code, but there are really no limitation of what you can do with pipes :)

Roosteridk commented 1 year ago

Wow, this is awesome! Thank you so much for sharing this. I had no idea this was even possible.

I guess then, dynamic keys could serve as syntactic sugar over what is basically a nested for loop.

StarKen69 commented 1 year ago

Hello, I am using this library and I would like to know if there is a way to change "Teléfono Fijo De Cerámica Para El Hogar Decoración Retro ITM195" by simply name or price, here is an example

[

  {
    'Teléfono Fijo De Cerámica Para El Hogar Decoración Retro ITM195': 'Amplificador De Señal De Celular Repetidor Gsm',
    '$  28.990  -33%$  43.500  (9)PatrocinadoAgregar': '$  129.990  -23%$  168.725  PatrocinadoAgregar'
  },
  {
    'Teléfono Fijo De Cerámica Para El Hogar Decoración Retro ITM195': 'Apple iPhone 14 256 GB',
    '$  28.990  -33%$  43.500  (9)PatrocinadoAgregar': '$  959.990  $  1.099.990  (25)Agregar'
  },
  {
    'Teléfono Fijo De Cerámica Para El Hogar Decoración Retro ITM195': 'Apple iPhone 14 256 GB',
    '$  28.990  -33%$  43.500  (9)PatrocinadoAgregar': '$  959.990  $  1.099.990  (25)Agregar'
  },
]
[

  {
    name : 'Amplificador De Señal De Celular Repetidor Gsm',
    price : '$  129.990  -23%$  168.725  PatrocinadoAgregar'
  },
  {
    name :'Apple iPhone 14 256 GB',
   price :  '$  28.990  -33%$  43.500  (9)PatrocinadoAgregar': '$  959.990  $  1.099.990  (25)Agregar'
  },
  {
   name : 'Apple iPhone 14 256 GB',
   price :  '$  959.990  $  1.099.990  (25)Agregar'
  },
]

image

pd: thanks for creating this library it was quite tedious to wait for Cheerio.