Hoping you guys can help with this. I have thousands of these tables to convert.
Example
<table>
<thead>
<tr>
<td>Institutional Metrics</td>
<td>Institutional Targets</td>
</tr>
</thead>
<tbody>
<tr>
<td>example</td>
<td>example 2</td>
</tr>
</tbody>
</table>
For each <td> in the <thead> section it should be a <th scope="col">. Every first <td> in the <tbody> should be <th scope="row">.
I have tried a few different things, nothing seems to work. Any help would be great!
EDIT
I think what added to this is they are being imported from MS Word. So I've written so code to clean them up a bit.
function cleanUp(){
var searchInput = document.getElementById('userInput').value;
//clense it
searchInput = searchInput.replace( /\btd\s\w\w\w\w\w\W\W\d\d\d\W\s\w\w\w\w\w\w\W\W\w\w\w\W/g, 'td');
searchInput = searchInput.replace( /(<td>)+/g, '<td>\n');
searchInput = searchInput.replace( /(<tr>)/, '<thead>\n<tr>');
searchInput = searchInput.replace( /(<\/tr>)/, '</tr>\n</thead>\n<tbody>');
searchInput = searchInput.replace( /(<\/table>)/, '</tbody>\n</table>');
//replacement
//output
document.getElementById('updated').innerHTML = searchInput;
document.getElementById('howTo').style.display ='block';
}
<div><textarea placeholder="Paste in your code" style="width:900px; height:300px;" id="userInput"></textarea></div>
<div><textarea style="width:900px; height:300px;" id="updated"></textarea></div>
<div>
<button onclick="cleanUp()">Run Script</button>
<br>
<div id="howTo" style="display: none;"><p>Use the <strong>|</strong> for Excel data import and selection separation. <a id="download" href="">Download .txt file</a>.</p>
</div>
Updated - FINAL
Thanks everybody! Got it working!
<script type="text/javascript">
function cleanUp(){
var searchInput = document.getElementById('userInput').value;
//clense it
searchInput = searchInput.replace( /\btd\s\w\w\w\w\w\W\W\d\d\d\W\s\w\w\w\w\w\w\W\W\w\w\w\W/g, 'td');
searchInput = searchInput.replace( /(<td>)+/g, '<td>\n');
searchInput = searchInput.replace( /(<tr>)/, '<thead>\n<tr>');
searchInput = searchInput.replace( /(<\/tr>)/, '</tr>\n</thead>\n<tbody>');
searchInput = searchInput.replace( /(<\/table>)/, '</tbody>\n</table>');
//output
document.getElementById('updated').innerHTML = searchInput;
//final cleaning
document.querySelectorAll('table > thead > tr > td').forEach(function(el) {
var th = document.createElement("th");
th.setAttribute("scope", "col");
th.innerHTML = el.innerHTML
el.parentNode.replaceChild(th, el);
});
document.querySelectorAll('table > tbody > tr > td:first-child').forEach(function(el) {
var th = document.createElement("th");
th.setAttribute("scope", "row");
th.innerHTML = el.innerHTML
el.parentNode.replaceChild(th, el);
});
var finalInput = document.getElementById('updated').innerHTML;
//output
document.getElementById('updatedFinal').innerHTML = finalInput;
}
</script>
-
Unclear what the goal is.... You want to replace the elements with JavaScript?epascarello– epascarello2017年08月23日 14:21:33 +00:00Commented Aug 23, 2017 at 14:21
-
Specific find & replace potentially.Christopher Marshall– Christopher Marshall2017年08月23日 14:21:58 +00:00Commented Aug 23, 2017 at 14:21
-
1are you open to a jquery solution?treyBake– treyBake2017年08月23日 14:23:20 +00:00Commented Aug 23, 2017 at 14:23
-
2Best solution, fix it on the file system.... Fixing it on the clientside is going to cause flashing of content since you have to wait for it to be loaded so you can select it and replace it.epascarello– epascarello2017年08月23日 14:25:31 +00:00Commented Aug 23, 2017 at 14:25
-
1Sure, if jQuery can do it, I am all for it.RW Hammond– RW Hammond2017年08月23日 14:25:48 +00:00Commented Aug 23, 2017 at 14:25
5 Answers 5
For an alternative solution this could be use
Code Sample:
Note: my code is inspired from @kukkuz's answer
document.querySelectorAll('table > thead > tr > td').forEach(function(el) {
var th = document.createElement("th");
th.setAttribute("scope", "col");
th.innerHTML = el.innerHTML
el.parentNode.replaceChild(th, el);
});
document.querySelectorAll('table > tbody > tr > td:first-child').forEach(function(el) {
var th = document.createElement("th");
th.setAttribute("scope", "row");
th.innerHTML = el.innerHTML
el.parentNode.replaceChild(th, el);
});
table,
td,
th {
border: 1px solid #ccc;
}
th[scope=row] {
color: red;
}
th[scope=col] {
color: blue;
}
<table>
<thead>
<tr>
<td>Institutional Metrics</td>
<td>Institutional Targets</td>
</tr>
</thead>
<tbody>
<tr>
<td>example</td>
<td>example 2</td>
</tr>
</tbody>
</table>
Comments
Well best thing is to change the markup itself. Anyway you can replace the outerHTML of the tds that need to be targeted - see demo below using vanilla javascript:
Array.prototype.forEach.call(document.querySelectorAll('table > thead > tr > td'), function(e){
e.outerHTML = '<th scope="row">' + e.innerHTML + '</th>';
});
Array.prototype.forEach.call(document.querySelectorAll('table > tbody > tr > td:first-child'), function(e){
e.outerHTML = '<th scope="row">' + e.innerHTML + '</th>';
});
th[scope=row] {
color: red;
}
<table>
<thead>
<tr>
<td>Institutional Metrics</td>
<td>Institutional Targets</td>
</tr>
</thead>
<tbody>
<tr>
<td>example</td>
<td>example 2</td>
</tr>
</tbody>
</table>
Updated answer using DOMParser that converts a html string entered in a textarea:
function cleanUp() {
var parser = new DOMParser();
var html = parser.parseFromString(document.getElementById('userInput').value, "text/html");
Array.prototype.forEach.call(html.querySelectorAll('table > thead > tr > td'), function(e) {
e.outerHTML = '<th scope="row">' + e.innerHTML + '</th>';
});
Array.prototype.forEach.call(html.querySelectorAll('table > tbody > tr > td:first-child'), function(e) {
e.outerHTML = '<th scope="row">' + e.innerHTML + '</th>';
});
document.getElementById('updatedFinal').value = html.querySelector('table').outerHTML;
}
<div><textarea placeholder="Paste in your code" style="width:900px; height:300px;" id="userInput"></textarea></div>
<div>
<button onclick="cleanUp()">Run Script</button>
</div>
<div><textarea style="width:900px; height:300px;" id="updatedFinal"></textarea></div>
Comments
Use replaceWith. but it will replace the entire thing include text content. To keep the text content, first copy it to another variable and then append it to new element.
$('tr').each(function() {
var content = $('<th scope="col">');
content.html($(this).html());
$(this).replaceWith(content);
});
$('td:first-child').each(function() {
var content = $('<th scope="row">');
content.html($(this).html());
$(this).replaceWith(content);
});
console.log($('table').html());
<script src="https://ajax.googleapis.com/ajax/libs/jquery/2.1.1/jquery.min.js"></script>
<table>
<thead>
<tr>
<td>Institutional Metrics</td>
<td>Institutional Targets</td>
</tr>
</thead>
<tbody>
<tr>
<td>example</td>
<td>example 2</td>
</tr>
</tbody>
</table>
Comments
Here is a simple and pure JavaScript solution.
var theadTds = document.querySelectorAll('thead td')
theadTds.forEach(function(td){
td.setAttribute("scope", "row")
})
var tbodyTds = document.querySelectorAll('tbody tr>td:first-child')
tbodyTds.forEach(function(td){
td.setAttribute("scope", "row")
})
Comments
You can use replaceWith method.
replaceWithfunction replaces each element in the set of matched elements with the provided new content and return the set of elements that was removed.
$('thead tr').each(function(){
$(this).find('td').each(function(){
$(this).replaceWith('<th scope="col">'+$(this).html()+'</th>');
});
});
$('tbody tr').each(function(){
$(this).find('td').each(function(){
$(this).replaceWith('<th scope="row">'+$(this).html()+'</th>');
});
});
console.log($('table').html());
<script src="https://ajax.googleapis.com/ajax/libs/jquery/2.1.1/jquery.min.js"></script>
<table>
<thead>
<tr>
<td>Institutional Metrics</td>
<td>Institutional Targets</td>
</tr>
</thead>
<tbody>
<tr>
<td>example</td>
<td>example 2</td>
</tr>
</tbody>
</table>