How do I loop through XML nodes in JavaScript? - javascript

I'm trying to loop through XML nodes containing information about users to create an HTML table on my website.
This is what the XML looks like:
<websites_name>
<user>...</user>
<user>...</user>
.
.
.
</websites_name>
And this is the code I'm trying to parse it with:
for(var user in xmlhttp.getElementsByTagName('user')){ //fix this row to me
//Create a new row for tbody
var tr = document.createElement('tr');
document.getElementById('tbody').appendChild(tr);
}
UPDATE
xmlhttp = new XMLHttpRequest();
xmlhttp.open("GET","some URL",true);
xmlhttp.send();
var xmlDoc = xmlhttp.responseXML;
var root = xmlDoc.getElementsByTagName('websites_name');
for(var i=0, i<root[0].childNodes.length,i++){
//Create a new row for tbody
var tr = document.createElement('tr');
document.getElementById('tbody').appendChild(tr);
}

One of the least intuitive things about parsing XML in JavaScript is that the text inside the element tags is actually a node you have to traverse into.
Assuming it's <user>text data</user>, you not only have to traverse into the text node of the user element to extract your text data, but you have to create a text node with that data in the DOM to see it. See nodeValue and and createtextnode:
// get XML
var xml = xhr.responseXML;
// get users
var users = xml.getElementsByTagName("user");
for (var i = 0; i < users.length; i++) {
var user = users[i].firstChild.nodeValue;
var tr = document.createElement("tr");
var td = document.createElement("td");
var textNode = document.createTextNode(user);
td.appendChild(textNode);
tr.appendChild(td);
document.getElementById("tbody").appendChild(tr);
}

Related

Export javascript loop to CSV

Suppose I have this loop code.
for (var i = 0; i < originList.length; i++) {
var results = response.rows[i].elements;
for (var j = 0; j < results.length; j++) {
outputDiv.innerHTML += results[j].distance.text + ',';
}
}
I want to export the outputDiv.innerHTML into CSV with this code, but it doesn't work.
function downloadFile(fileName, urlData) {
var aLink = document.createElement('a');
aLink.download = fileName;
aLink.href = urlData;
var event = new MouseEvent('click');
aLink.dispatchEvent(event);
}
downloadFile('output.csv', 'outputDiv.innerHTML/csv;charset=UTF-8,' + encodeURIComponent(outputDiv.innerHTML));
What should I do? I'm new at this. Thank you.
This solution is in JavaScript. I added an event listener to the button so when it is clicked, it will grab the outerHTML of <table>.
outerHTML essentially includes the opening and closing tags of the element as well as the content whereas innerHTML does not include the opening and closing tags.
From MDN Web Docs
The outerHTML attribute of the Element DOM interface gets the serialized HTML fragment describing the element including its descendants. It can also be set to replace the element with nodes parsed from the given string.
When the innerText is extracted from the all rows and columns. download_csv is called.
You can download the data using a Blob object which is a file-like object of immutable, raw data.
document.querySelector("button").addEventListener("click", function () {
let html = document.querySelector("table").outerHTML;
exportToCSV(html, "table.csv");
});
function exportToCSV(html, filename) {
let csv = [];
// grab all rows inside table
let rows = document.querySelectorAll("table tr");
let row, cols;
for (let i = 0; i < rows.length; i++) {
row = []; // will hold innerText of all columns
// retrieve all columns of row
cols = rows[i].querySelectorAll("td, th");
for (let j = 0; j < cols.length; j++){
// push column innerText
row.push(cols[j].innerText);
}
// push all innerText into CSV
csv.push(row.join(","));
}
console.log("Extracted content from html:",csv);
// Download CSV
download_csv(csv.join("\n"), filename);
}
function download_csv(csv, filename) {
let csvFile;
let downloadLink;
// CSV FILE
csvFile = new Blob([csv], {type: "text/csv"});
// create an element and set the file name.
downloadLink = document.createElement("a");
downloadLink.download = filename;
// We have to create a link to the file
downloadLink.href = window.URL.createObjectURL(csvFile);
// prevent link from being shown
downloadLink.style.display = "none";
// Add the link to your DOM
document.body.appendChild(downloadLink);
// start the download
downloadLink.click();
}
<table>
<tr><th>Name</th><th>Age</th><th>Country</th></tr>
<tr><td>Tony</td><td>26</td><td>USA</td></tr>
<tr><td>Levi</td><td>19</td><td>Spain</td></tr>
<tr><td>Calvin</td><td>32</td><td>Russia</td></tr>
</table>
<button>Export HTML table to CSV file</button>
I do not know what are you trying to achieve in your last line, but that does not look like a dataURL, a dataURL looks like:
data:[][;base64],
Now that being said, the idea is to create an object url through a combination of Blob and window.URL.createObjectURL:
function dL(input,fileName){
var blob = new Blob(input,{type:"text/csv"}),
url = window.URL.createObjectURL(blob),
aElem = document.createElement("a"),
fileName = "deogenResults.txt";
aElem.setAttribute("href",url);
aElem.setAttribute("download",fileName);
if (window.navigator.constructor.prototype.hasOwnProperty("msSaveBlob")) {
window.navigator.msSaveBlob(blob,fileName);
} else if ("download" in aElem) {
aElem.click();
} else {
window.open(url,"_blank");
}
setTimeout(function(){window.URL.revokeObjectURL(url)},2000);
}
Use it like this: dL(outputDiv.innerHTML,"someName")
It is important to remind you that some browsers might not allow click to trigger on an element that is NOT in the DOM yet, in that case you might want to append the a element to the body, set it invisible and then remove it inside setTimeout.
I wrote it in plain ES5, you can adapt with const,Promise instead of setTimeout etc declarations accordingly.
A good answer here by dandavis:
It uses a library by http://danml.com/js/download.js you make sure your div contents contains comma seperated content.
var csv = jQuery(".list").map(function(a, i) {
return $.trim($(this).text()).split(/\s*\n\s*/).join(",");
}).toArray().join("\r\n");
alert(csv); // Contents
// Download
// download(csv, "tabledata.csv", "text/csv");
<script src="https://cdnjs.cloudflare.com/ajax/libs/jquery/3.3.1/jquery.min.js"></script>
<script src="http://danml.com/js/download.js"></script> <!-- CSV -->
<div class="list">
1, 2, 3
</div>

Error "Cannot read property 'appendChild' of null at generateTable"

Can someone please shine some light on my this error is tossed? outputTable is properly referenced, and my JS file with the array countries is properly formatted.
I reckon I am appending erroneously, but I have tried all that I can.
PS if youre going to downvote, at least please tell me how to improve my questions in the future. I couldnt find a different question that exists already that matches my issue.
window.onload = generateTable();
function generateTable() {
// get the reference for the body
var outputTable = document.getElementById('outputTable');
// revoke existing Body element
if (outputTable) {
outputTable.removeChild(outputTable);
}
// creates a <tbody> element
var tableBody = document.createElement('tbody');
// creating all table rows
for (var i = 0; i < countries.length; i++) {
// creates a table row
var row = document.createElement('tr');
// create table column for flag
var colFlag = document.createElement('td');
//create image element in flag column
var flag = document.createElement('img');
flag.src = 'flags/' + countries[i].Code.toLowerCase() + '.png';
flag.alt = countries[i].Code;
row.appendChild(colFlag);
//append flag to flag column
colFlag.appendChild(flag);
// create table column for Code
var colCode = document.createElement('td');
//append code to code column
colCode.appendChild(document.createTextNode(countries[i].Code));
row.appendChild(colCode);
// create table column for country //**ENGLISH */
var colCountry = document.createElement('td');
colCountry.appendChild(document.createTextNode(countries[i].Name.English));
row.appendChild(colCountry);
// create table column for continent
var colCont = document.createElement('td');
colCont.appendChild(document.createTextNode(countries[i].Continent));
row.appendChild(colCont);
// create table column for area
var colArea = document.createElement('td');
colArea.appendChild(document.createTextNode(countries[i].AreaInKm2));
row.appendChild(colArea);
// create table column for population
var colPop = document.createElement('td');
colPop.appendChild(document.createTextNode(countries[i].Population));
row.appendChild(colPop);
// create table column for capital of country
var colCap = document.createElement('td');
colCap.appendChild(document.createTextNode(countries[i].Capital));
row.appendChild(colCap);
// attach columns to row
tableBody.appendChild(row);
outputTable.appendChild(tableBody);
}
// add the row to the end of the table body
document.body.appendChild(outputTable);
}

Format data from database if data contains a tab-sign

I have a website in wich users input text into a textarea.
This text is saved into a database table and is later shown in a div element
Sometimes a user paste data from excel into the textarea, i wish to retain the table layout from excel after i pull it from the database and present it on my webpage
Example:
test cat1 cat2
data1 1 2
data2 3 5
data3 6 5
Is it possible (probably with js) that on loading the page a code checks if a tab-sign is in the data? And if yes.. format that data as a html table?
TRY As below. Just giving you idea.
var body = document.getElementsByTagName('body')[0];
var text = document.getElementByID("txtareaID").value;
var isTab = text.indexOf("\t");
if(isTab != '-1')
{
var tableCell = text.split("\t");
var table = document.createElement('table');
var tbdy = document.createElement('tbody');
var tr = document.createElement('tr');
for (var i = 0; i < tableCell.length ; i++) {
var td = document.createElement('td');
td.innerText = tableCell[i];
tr.appendChild(td);
}
tbdy.appendChild(tr);
}
tbl.appendChild(tbdy);
body.appendChild(tbl);
}
You can check for tab characters using \t to see if the character exists in the string. Something like this
var text = "test cat1 cat2 data1 1 2 data2 3 5 data3 6 5";
var tabsFound = text.indexOf("\t");

Creating separate arrays from TH data in different tables

I'm having a bit of an issue with some JS/JQuery. I am using some script to create an array from the data within the <TH> tags, then doing some formatting of that data to create new content and styles for a responsive table.
<script>
$( document ).ready(function() {
// Setup an array to collect the data from TH elements
var tableArray = [];
$("table th").each(function(index){
var $this = $(this);
tableArray[index] = $this.text();
});
console.log(tableArray);
alert(tableArray);
// Create class name based on th values and store as variable
var tableString = tableArray.join();
tableString = tableString.replace(/,/g, '_')
tableString = tableString.replace(/ /g, '-')
var tableClass = ".responsive-table."+tableString;
console.log(tableClass);
// Push tableClass variable into the table HTML element
var applyTableClass = tableClass;
applyTableClass = applyTableClass.replace(/\./gi, " ") //converts the style declaration into something i can insert into table tag (minus the dots!)
console.log(applyTableClass);
$( "table" ).addClass( applyTableClass );
// Create a loop which will print out all the necessary css declarations (into a string variable) based on the amount of TH elements
var i = 0;
var styleTag = "";
while (tableArray[i]) {
styleTag += tableClass+" td:nth-of-type("+[i+1]+"):before { content: '"+tableArray[i]+"'; }";
i++;
}
// Push the styleTag variable into the HTML style tag
$('style#jquery-inserted-css').html(styleTag);
// Below is just a test script to check that values are being collected and printed properly (use for testing)
//$('#css_scope').html('<p>'+styleTag+'</p>');
});
</script>
This works great when there is a single table within the page, but not if there is additional tables. The reason is that the loop that creates the array keeps going and does not know to stop and return at the end of one table, then create a new array for the next table. I am imagining that I need to set up a loop that creates the arrays as well.
This is where I am quit stuck with my limited scripting skills. Can anyone please suggest a way to get my code to loop through multiple tables, to create multiple arrays which then create separate style declarations?
You can loop through each table instead of querying all tables at once:
$( document ).ready(function() {
$("table").each(function () {
var tableArray = [];
$(this).find("th").each(function (index) {
var $this = $(this);
tableArray[index] = $this.text();
});
console.log(tableArray);
alert(tableArray);
// Create class name based on th values and store as variable
var tableString = tableArray.join();
tableString = tableString.replace(/,/g, '_')
tableString = tableString.replace(/ /g, '-')
var tableClass = ".responsive-table." + tableString;
console.log(tableClass);
// Push tableClass variable into the table HTML element
var applyTableClass = tableClass;
applyTableClass = applyTableClass.replace(/\./gi, " ") //converts the style declaration into something i can insert into table tag (minus the dots!)
console.log(applyTableClass);
$(this).addClass(applyTableClass);
// Create a loop which will print out all the necessary css declarations (into a string variable) based on the amount of TH elements
var i = 0;
var styleTag = "";
while (tableArray[i]) {
styleTag += tableClass + " td:nth-of-type(" + [i + 1] + "):before { content: '" + tableArray[i] + "'; }";
i++;
}
// Push the styleTag variable into the HTML style tag
$('style#jquery-inserted-css').append(styleTag);
// Below is just a test script to check that values are being collected and printed properly (use for testing)
//$('#css_scope').html('<p>'+styleTag+'</p>');
});
});
Note that I change $("table th") to $(this).find("th"), $("table") to $(this) and $('style#jquery-inserted-css').html(styleTag); to $('style#jquery-inserted-css').append(styleTag);.
Hope this help.

what's the easiest method to append a TR to a table by javascript?

If the table id is known – so the table can be obtained with docoument.getElementById(table_id) – how can I append a TR element to that table in the easiest way?
The TR is as follows:
<tr><td><span>something here..</span></td></tr>
The first uses DOM methods, and the second uses the non-standard but widely supprted innerHTML
var tr = document.createElement("tr");
var td = document.createElement("td");
var span = document.createElement("span");
var text = document.createTextNode("something here..");
span.appendChild(text);
td.appendChild(span);
tr.appendChild(td);
tbody.appendChild(tr);
OR
tbody.innerHTML += "<tr><td><span>something here..</span></td></tr>"
The most straightforward, standards compliant and library-independent method to insert a table row is using the insertRow method of the table object.
var tableRef = document.getElementById(tableID);
// Insert a row in the table at row index 0
var newRow = tableRef.insertRow(0);
P.S. Works in IE6 too, though it may have some quirks at times.
Using jQuery:
$('#table_id > tbody').append('<tr><td><span>something here..</span></td></tr>');
I know some may cringe at the mention of jQuery. Including a framework to do just this one thing is probably overkill. but I rarely find that I only need to do "just one thing" with javascript. The hand-coded solution is to create each of the elements required, then add them in the proper sequence (from inner to outer) to the other elements, then finally add the new row to the table.
If you're not opposed to using jQuery, you can use either of the following where "tblId" is the id of your table and "_html" is a string representation of your table row:
$(_html).insertAfter("#tblId tr:last");
or
$("#tblId tr:last").after(_html);
i use this function to append a bunch of rows into a table. its about 100% faster then jquery for large chunks of data. the only downside is that if your rows have script tags inside of them, the scripts wont be executed on load in IE
function appendRows(node, html){
var temp = document.createElement("div");
var tbody = node.parentNode;
var nextSib = node.nextSibling;
temp.innerHTML = "<table><tbody>"+html;
var rows = temp.firstChild.firstChild.childNodes;
while(rows.length){
tbody.insertBefore(rows[0], nextSib);
}
}
where node is the row to append after, and html is the rows to append
Really simple example:
<html>
<table id = 'test'>
<tr><td>Thanks tvanfosson!</td></tr>
</table>
</html>
<script type="text/javascript" charset="utf-8">
var table = document.getElementById('test');
table.innerHTML += '<tr><td><span>something here..</span></td></tr>';
</script>
I use this, works softly:
var changeInnerHTMLOfMyCuteTbodyById = function (id_tbody, inner_html)
{
//preparing
var my_tbody = document.getElementById (id_tbody);
var my_table = my_tbody.parentNode;
my_table.removeChild (my_tbody);
//creating dom tree
var html = '<table style=\'display:none;\'><tbody id='+ id_tbody+'>' +
inner_html + '</tbody></table>';
var tmp_div = document.createElement ('div');
tmp_div.innerHTML = html;
document.body.appendChild (tmp_div);
//moving the tbody
my_table.appendChild (document.getElementById (id_tbody));
}
You can do this:
changeInnerHTMLOfMyCuteTbodyById('id_tbody', document.getElementById ('id_tbody').innerHTML + '<tr> ... </tr>');

Categories