我如何使用香草javascript将数据从html表转换为对象数组

时间:2019-05-06 12:48:31

标签: javascript

众所周知,数据存储的“对象数组”格式非常适合数据持久化。如果JavaScript专家帮助我找到如何使用原始JavaScript读取此HTML表并将数据从其中传输到以下对象数组中的答案,我将非常感激。

我产生了大量的代码,大部分是比较两个对象数组。不幸的是,我离解决方案还差得远。

要从中抓取数据的表:

<table>
  <tbody>
    <tr>
      <td colspan="3">Canada</td>
    </tr>
    <tr>
      <td>Toronto</td>
      <td>Montreal</td>
      <td>Vancouver</td>
    </tr>
    <tr>
      <td colspan="3">USA</td>
    </tr>
    <tr>
       <td>New York</td>
       <td>Chicago</td>
       <td>Boston</td>
    </tr>
    <tr>
       <td>Washington</td>
       <td>Detroit</td>
       <td>Los Angeles</td>
    </tr>
  </tbody>
</table>

预期结果如下:

 [
 {"country":"Canada","city":"Toronto"},
 {"country":"Canada","city":"Montreal"},
 {"country":"Canada","city":"Vancouver"},
 {"country":"USA","city":"New York"},
 {"country":"USA","city":"Chicago"},
 {"country":"USA","city":"Boston"},
 {"country":"USA","city":"Washington"},
 {"country":"USA","city":"Detroit"},
 {"country":"USA","city":"Los Angeles"}
 ]

代码有效,与方法不同:

let theResult = [];
    arrayOfCountriesAndCitiesObjects.forEach((item, iIndex) => {
        arrayOfCitiesObjects.forEach((elem, eIndex) => {
            if(item.city !== elem.city && item.iIndex < elem.eIndex) theResult.push(copy(elem, item)); 
        });
    });
    function copy(firstObj) {
      for (let i = 1; i < arguments.length; i++) {
        let arg = arguments[i];
        for (let key in arg) {
          firstObj[key] = arg[key];
        }
      }
      return firstObj;
    }

6 个答案:

答案 0 :(得分:2)

您可以将colSpan === 3的值存储为国家,并将所有其他值作为城市推送到结果集中。

这适用于不带任何库的纯Javascript。

var result = [],
    country = '';

document
    .querySelectorAll('table td')
    .forEach(td => {
        if (td.colSpan === 3) {
            country = td.innerHTML;
            return;
        }
        result.push({ country, city: td.innerHTML.trim() });
    });

console.log(result);
<table>
  <tbody>
    <tr>
      <td colspan="3">Canada</td>
    </tr>
    <tr>
      <td>Toronto</td>
      <td>Montreal</td>
      <td>Vancouver</td>
    </tr>
    <tr>
      <td colspan="3">USA</td>
    </tr>
    <tr>
       <td>New York</td>
       <td>Chicago</td>
       <td>Boston</td>
    </tr>
    <tr>
       <td>Washington</td>
       <td>Detroit</td>
       <td>Los Angeles</td>
    </tr>
  </tbody>
</table>

答案 1 :(得分:1)

您可以使用for遍历每个tr。在每个td上找到tr,如果只有1,则将文本存储在currentCountry变量中。如果不止一个,则将对象推送到结果变量。

var currentCountry = "";
var result = [];

var tr = document.querySelectorAll('table tr');

for (var i = 0; i < tr.length; i++) {
  var td = tr[i].querySelectorAll('td');

  if (td.length === 1) currentCountry = td[0].innerHTML;
  else if (td.length > 1) {
    for (var a = 0; a < td.length; a++) {
      result.push({country: currentCountry,city: td[a].innerHTML});
    }
  }
}

console.log(result);
<table>
  <tbody>
    <tr>
      <td colspan="3">Canada</td>
    </tr>
    <tr>
      <td>Toronto</td>
      <td>Montreal</td>
      <td>Vancouver</td>
    </tr>
    <tr>
      <td colspan="3">USA</td>
    </tr>
    <tr>
      <td>New York</td>
      <td>Chicago</td>
      <td>Boston</td>
    </tr>
    <tr>
      <td>Washington</td>
      <td>Detroit</td>
      <td>Los Angeles</td>
    </tr>
  </tbody>
</table>

答案 2 :(得分:1)

使用减少

 const items = document.querySelectorAll('table tbody td')

 const results = [...items].reduce((allItems, item)=>{
   if(item.getAttribute('colspan') === '3'){
     allItems['country'] = item.textContent
     return allItems
   }
   allItems.push({country: allItems['country'],city:item.textContent})
   return allItems
 },[])

答案 3 :(得分:1)

不太优雅,但对我来说稍微更全面(the fastest用于更大的输入数据样本)reduce()解决方案:

const result = [...document.getElementsByTagName('td')].reduce((res, item) => (item.getAttribute('colspan') == 3 ? res.country = item.textContent : res.obj = [...(res.obj || []), {country: res.country, city: item.textContent}], res), {}).obj;

console.log(result);
<table>
  <tbody>
    <tr>
      <td colspan="3">Canada</td>
    </tr>
    <tr>
      <td>Toronto</td>
      <td>Montreal</td>
      <td>Vancouver</td>
    </tr>
    <tr>
      <td colspan="3">USA</td>
    </tr>
    <tr>
       <td>New York</td>
       <td>Chicago</td>
       <td>Boston</td>
    </tr>
    <tr>
       <td>Washington</td>
       <td>Detroit</td>
       <td>Los Angeles</td>
    </tr>
  </tbody>
</table>

答案 4 :(得分:0)

您需要为所有包含国家名称的<tr>分配一个特殊的类。然后使用querySelectorAll并使用forEach循环。

const tr = document.querySelectorAll('tr');

const arr = []
let count = '';

tr.forEach(x => {
  if(x.classList.contains('head')){
    count = x.children[0].innerHTML
  }
  else{
    let child = [...x.querySelectorAll('td')]
    arr.push(...child.map(a => ({country:count,city:a.innerHTML})))
  }
})

console.log(arr)
<table>
  <tbody>
    <tr class="head">
      <td  colspan="3">Canada</td>
    </tr>
    <tr>
      <td>Toronto</td>
      <td>Montreal</td>
      <td>Vancouver</td>
    </tr>
    <tr class="head" >
      <td colspan="3">USA</td>
    </tr>
    <tr>
       <td>New York</td>
       <td>Chicago</td>
       <td>Boston</td>
    </tr>
    <tr>
       <td>Washington</td>
       <td>Detroit</td>
       <td>Los Angeles</td>
    </tr>
  </tbody>
</table>

答案 5 :(得分:0)

var country = null, result = [];
var tds = Array.from(document.querySelectorAll("#myTable tbody tr td"));
for (var i = 0; i < tds.length; i++) {
	let item = tds[i];
	if (item.getAttribute("colspan") == "3") {
		country = item.innerText;
		continue;
	}
	
	result.push({ country: country, city: item.innerText });
}
console.log(result);
<table id="myTable">
	<tbody>
		<tr>
			<td colspan="3">Canada</td>
		</tr>
		<tr>
			<td>Toronto</td>
			<td>Montreal</td>
			<td>Vancouver</td>
		</tr>
		<tr>
			<td colspan="3">USA</td>
		</tr>
		<tr>
			<td>New York</td>
			<td>Chicago</td>
			<td>Boston</td>
		</tr>
		<tr>
			<td>Washington</td>
			<td>Detroit</td>
			<td>Los Angeles</td>
		</tr>
	</tbody>
</table>