2

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>
asked Aug 23, 2017 at 14:20
9
  • Unclear what the goal is.... You want to replace the elements with JavaScript? Commented Aug 23, 2017 at 14:21
  • Specific find & replace potentially. Commented Aug 23, 2017 at 14:21
  • 1
    are you open to a jquery solution? Commented Aug 23, 2017 at 14:23
  • 2
    Best 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. Commented Aug 23, 2017 at 14:25
  • 1
    Sure, if jQuery can do it, I am all for it. Commented Aug 23, 2017 at 14:25

5 Answers 5

1

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>

answered Aug 23, 2017 at 14:57
Sign up to request clarification or add additional context in comments.

Comments

1

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>

answered Aug 23, 2017 at 14:31

Comments

0

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>

answered Aug 23, 2017 at 14:31

Comments

0

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")
})
answered Aug 23, 2017 at 14:36

Comments

0

You can use replaceWith method.

replaceWith function 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>

answered Aug 23, 2017 at 14:29

3 Comments

So you suggest that he should replace thousands of tables in runtime? On...the client side?
It won't be a at runtime. I am going to cut and paste them from word into the documents.
obviously you don't want to do that but you can't access the filesystem and manipulate files with a jquery script...

Your Answer

Draft saved
Draft discarded

Sign up or log in

Sign up using Google
Sign up using Email and Password

Post as a guest

Required, but never shown

Post as a guest

Required, but never shown

By clicking "Post Your Answer", you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.