Генерация объекта json из данных - PullRequest
2 голосов
/ 19 января 2020

У меня возникли проблемы при создании объекта json в формате ниже по данным ниже. Fiddle

[ { Invoice: 
    { 
       headers: { date: "15-01-2020", buyer: "McDonalds", order: "145632"}, 
       items: { name: "Big Mac",   quantity: "5",  rate: "20.00"}, 
       items: { name: "Small Mac", quantity: "10", rate: "10.00"} 
    } 
  } 
, { Invoice: { // Other invoices go here, I've used just one for this example} } 
] 
<div class="invoice">
  <div class="header">
    <div contenteditable data="date">15-Jan-2020</div>
    <div contenteditable  data="buyer">McDonalds</div>
    <div contenteditable  data="order">145632</div>
  </div>
  <div class="item">
    <div contenteditable data="name">Big Mac</div>
    <div contenteditable data="quantity">5</div>
    <div contenteditable data="rate">20.00</div>
  </div>
  <div class="item">
    <div contenteditable data="name">Small Mac</div>
    <div contenteditable data="quantity">10</div>
    <div contenteditable data="rate">10.00</div>
  </div>
</div>

<button>Loop</button>

jQuery

var button = $("button")
button.on("click",function() {  
  jsonObj =[];
  $('.invoice>.header>div, .invoice>.item>div').each(function(index,item) {
    console.log($(this).parent().attr('class'));
    console.log($(this).attr('data'),$(this).text());
    q = {}
    q ['header'] = $(this).parent().attr('class');
    q [$(this).attr('data')] = $(this).text();

    jsonObj.push(q);
   });
   console.log(jsonObj);
   console.log(JSON.stringify(jsonObj));
});

Я в итоге получаю такой объект, где ключи повторяется везде. Как я могу получить это право?

  [ { "header": "header", "date": "15-Jan-2020"} 
  , { "header": "header", "buyer": "McDonalds"} 
  , { "header": "header", "order": "145632"} 
  , { "header": "item", "name": "Big Mac"} 
  , { "header": "item", "quantity": "5"} 
  , { "header": "item", "rate": "20.00"} 
  , { "header": "item", "name": "Small Mac"} 
  , { "header": "item", "quantity": "10"} 
  , { "header": "item", "rate": "10.00"} 
  ] 

Ответы [ 2 ]

2 голосов
/ 19 января 2020

Чистый JS код для этого:

Примечания : Я изменил:
<div ... data="..."> ... </div>
на
<div ... data-ref="..."> ... </div>

для соответствия директивам HTML (см. https://developer.mozilla.org/en-US/docs/Web/HTML/Global_attributes/data-*)

const jsonObj  = []
  ,   inVoices = document.querySelector('.invoice')
  ,   subDivOf = (parent,query) => [...parent.querySelectorAll(query)]
  ,   dataElms = (ac,el)=>{ac[el.dataset.ref]=el.textContent;return ac }
  ;

Loop.onclick=_=>
  {
  jsonObj.push( { Invoice: getInVoicesValues() } )
  console.clear()
  console.log( jsonObj )
  }
function getInVoicesValues() 
  {
  const headers  = subDivOf(inVoices,'.header>div').reduce(dataElms,{})
    ,   items    = subDivOf(inVoices,'.item').reduce((accI,itm)=>
                      {
                      accI.push( subDivOf(itm, 'div').reduce(dataElms,{}))
                      return accI
                      },[])
      ;
  return { headers, items }      
  }
.as-console-wrapper {
    max-height: 100% !important;
    width: 70% !important;
    top: 0; left: 30% !important;
  }
  div.invoice>div:before {
    display:  block;
    content: attr(class) ' :';
  }
  div[contenteditable] {
    font: 12px Arial, Helvetica, sans-serif;
    margin: .3em;
    width: 12em;
    border : 1px solid grey; 
    padding:.2em 1em;
    margin-left:6em;
  }
  div[contenteditable]::before {
    display: inline-block;
    content: attr(data-ref);
    font-weight : bold;
    width: 4.9em;
    margin-left:-5.3em;
  }
<div class="invoice">
  <div class="header">
    <div contenteditable data-ref="date">15-Jan-2020</div>
    <div contenteditable data-ref="buyer">McDonalds</div>
    <div contenteditable data-ref="order">145632</div>
  </div>
  <div class="item">
    <div contenteditable data-ref="name">Big Mac</div>
    <div contenteditable data-ref="quantity">5</div>
    <div contenteditable data-ref="rate">20.00</div>
  </div>
  <div class="item">
    <div contenteditable data-ref="name">Small Mac</div>
    <div contenteditable data-ref="quantity">10</div>
    <div contenteditable data-ref="rate">10.00</div>
  </div>
</div>
    
<button id="Loop">Loop</button>

......................... запустить фрагменты в полноэкранном режиме для лучшего просмотра

второй метод

const jsonObj      = [];
const inVoicesElms = document.querySelectorAll('.invoice div');

Loop.onclick=_=>
  {
  jsonObj.push( { Invoice: getInVoicesValues() } )
  console.clear()
  console.log( jsonObj )
  }
function getInVoicesValues() 
  {
  let rep  = { headers:{}, items:[] }
    , cur  = null
    ;
  inVoicesElms.forEach(el =>
    {
    if (el.matches('.header'))
      {
      cur = rep.headers
      }
    else if (el.matches('.item'))
      {
      cur = {}
      rep.items.push(cur)
      }
    else // (el.matches('[contenteditable]'))
      {
      cur[el.getAttribute('data')] = el.textContent
      }
    })
  return rep
  }
.as-console-wrapper { max-height: 100% !important; width: 70% !important;
    top: 0; left: 30% !important;
  }
<div class="invoice">
  <div class="header">
    <div contenteditable data="date">15-Jan-2020</div>
    <div contenteditable data="buyer">McDonalds</div>
    <div contenteditable data="order">145632</div>
  </div>
  <div class="item">
    <div contenteditable data="name">Big Mac</div>
    <div contenteditable data="quantity">5</div>
    <div contenteditable data="rate">20.00</div>
  </div>
  <div class="item">
    <div contenteditable data="name">Small Mac</div>
    <div contenteditable data="quantity">10</div>
    <div contenteditable data="rate">10.00</div>
  </div>
</div>
    
<button id="Loop">Loop</button>
2 голосов
/ 19 января 2020

В вашем примере у вас есть объект с двумя одинаковыми ключами:

"items":{
    "name":"Big Mac",
    "quantity":"5",
    "rate":"20.00"
}
"items":{
    "name":"Small Mac",
    "quantity":"10",
    "rate":"10.00"
}

Это не сработает, потому что вы можете иметь только один, поэтому вам нужно изменить значение ключа items к массиву объектов:

"items":[
    {
        "name":"Big Mac",
        "quantity":"5",
        "rate":"20.00"
    },
    {
        "name":"Small Mac",
        "quantity":"10",
        "rate":"10.00"
    }
]

Код итерации может выглядеть следующим образом:

const jsonObj = [];

$('.invoice').each((index, item) => {
 const invoice = {
    header: {},
    items: []
 };

 $(item).find('.header > div').each((index, item) => {
    const key = $(item).attr('data');
    invoice.header[key] = $(item).text();
 });

 $(item).find('.item').each((index, item) => {
    const itemObj = {};

    $(item).find('div').each((index, item) => {
        const key = $(item).attr('data');
        itemObj[key] = $(item).text();
    });

    invoice.items.push(itemObj);
 });

 jsonObj.push({
    Invoice: invoice
 });
});

Основное отличие от вашей версии состоит в том, что он выполняет итерацию по шагам через dom. Сначала через каждый счет, затем через каждый заголовок счета и каждый элемент. Таким образом, легко построить нужную структуру.

Вот ссылка jsfiddle: https://jsfiddle.net/tara5/tanb174h/

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...