recently I reached out on here for some help regarding javascript. I needed something that parsed a CSV file and outputted it to HTML.
Someone was able to help me massively. only problem is that it outputs as a one row table. In the CSV file each row does not have a specific amount of columns/data meaning that the row data varies in length.
what I've been trying to do is write some if statements to only pick up things like 'Last name' or 'known for' so i can give some order to the results.
What is the best way to do this? I will need to style the output data so i'm thinking div id's would be better than tables. also, where abouts in the code should i edit (my javascript knowledge is very beginner).
if statement i tried (probably totally wrong):
function firstName($container){
var firstN = $container;
var n = firstN.includes("First Name");
if (n != 0){
document.getElementById("first_name").innerHTML="First name = ";
return;
}
}
main block of code (CSV file can be found at http://www.fooda.website/testResults.csv):
<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">
<html xmlns="http://www.w3.org/1999/xhtml">
<head>
<meta http-equiv="Content-Type" content="text/html; charset=utf-8" />
<script src="jquery-1.12.3.min.js" type="text/javascript">
</script>
<title>Untitled Document</title>
<script type="text/javascript">
// ============================
// Allow for a cached result
// ============================
var csvRows = [];
// ============================
// ============================
// Given an array of rows build a table.
// ============================
function buildTable(csvRows){
// Our base result
var $table = $("<table cellpadding=\"2\" cellspacing=\"0\"></table>");
// ============================
// For each row in the CSV build a <tr /> and append it to the <table />
// ============================
$table = csvRows.reduce(function($table, csvRow){
// For this demo just take the first few cells/columns
var csvRowCells = csvRow.split(",");
// Our base table row
var $tr = $("<tr>/tr>");
// ============================
// For each cell row build a <td /> and append it to the <tr />
// ============================
$tr = csvRowCells.reduce(function($tr, csvRowCell){
return $tr.append($("<td>/</td>").text(csvRowCell));
}, $tr);
// ============================
// Add our new <tr /> to the table then return the table
return $table.append($tr);
}, $table);
// ============================
return $table;
}
// ============================
// ============================
// Given an array of rows, randomly select one (as an array) and build a table with it.
// ============================
function fillContainerWithTable(csvRows, $container){
var randomRow = [csvRows[Math.floor(Math.random() * csvRows.length)]];
var $table = buildTable(randomRow);
$container.append($table);
}
// ============================
// ============================
// the click handler
// ============================
function myFunction(){
// some random csv I found...
var uri = "http://www.fooda.website/testResults.csv";
var $container = $("#wrap");
// You probably want a clean slate.
$container.empty();
// ============================
// If we have the data locally already just use it.
// ============================
if (csvRows.length !== 0){
console.log("using local data...");
fillContainerWithTable(csvRows, $container);
return;
}
// ============================
console.log("fetching remote data...");
$.get(uri, function(data){
csvRows = data.split("\n");
fillContainerWithTable(csvRows, $container);
});
}
// ============================
</script>
<style type="text/css">
body {
font-family: arial, helvetica, sans-serif;
font-weight: normal;
font-size: 13px;
color: #000;
text-align: left;
margin: 3px 0px;
}
#wrap {
padding: 20px;
}
#wrap table {
border: solid 1px;
border-collapse: collapse;
background-color: aliceblue;
height:400px;
width:100%;
}
#first_name {
height:200px;
width:200px;
background-color:#0C0;
}
</style>
</head>
<body>
<button onclick="myFunction()">Click me</button>
<div id="wrap"></div>
<div id="first_name">
</div><!--first_name-->
<script src="https://ajax.googleapis.com/ajax/libs/jquery/2.1.1/jquery.min.js"></script>
</body>
</html>
Thanks in advance!
Short answer is "this is a duplicate of the many 'how do I convert JSON into an HTML table' questions on SO" and in the end I'm just going to point you towards some of them, but I want to walk you through it.
CVS (comma-separated values) looks like
Col1,Col2,Col3,Col4
row1value1,row1value2,row1value3
row2value1,row2value2
row3value1,,row3value3,row3value4
While not necessarily the case, you can think of CSV as a very compact way text-only of writing a table, where each row's values are in the same order (like table columns) and empty cells look like ",,". If the above csv was a table (e.g. if you imported it into Excel etc), it would be
Col1 Col2 Col3 Col4
row1value1 row1value2 row1value3
row2value1 row2value2
row3value1 row3value3 row3value4
Your data, on the other hand, is actually a list of JSON "objects", one per line. In JSON, an object is contained within { } and is made up of "key/value" pairs. A JSON object looks like
{"key1":"value1", "key2":"value2"}
JSON lets you group objects into arrays. A JSON array is contained within [ ].
In JSON, the above table would look like
[{'Col1':'row1value1','Col2':'row1value2','Col3':'row1value3'},
{'Col1':'row1value1','Col2':'row1value2'},
{'Col1':'row1value1','Col3':'row1value3','Col4':'row1value4'}]
When working with JSON, you can say "loop through each object in an array" and "for the current object, give me the Col2 value." (Note this means related JSON objects don't have to list the key/value pairs in the same order, and you don't have to specify missing values.) If you knew every possible key in your array (in this case, that'd be Col1, Col2, Col3, and Col4) you could say
"Loop through the array, put each object in a <tr>, and for each
object first put the Col1 value in a <td>, then put the Col2 value
in a <td>, then put the Col3 value in a <td>, then put the Col4
value in a <td>."
That's exactly what you want to do… and it turns out there are already a bunch of tools out there to do it! The only thing standing between you and using them is putting a [ at the start of your file, a , at the end of every line except the last, and a ] at the end of the file. If you can do this, you're in luck. If this is static data, just open the data up in a text editor and use a find/replace to add in the end-of-line commas. If it's being generated on the fly, you'll have to come up with a way to add things (the solution will be something like tack on [, split the file by }, tack on each chunk of the split data followed by a , unless it's the last chunk, then tack on a ], and then run that through a JSON-to-HTML-table tool). I'll leave how exactly to do that up to you -- if you get stumped, definitely open up a new "how can I convert a list of json objects into a json array" question. I'm not a JSON expert, and I bet there's some standard way of doing it
Here are a couple promising JSON-to-HTML-table solutions. I'll be interested to hear if one of them works for you!
Convert json data to a html table
Parsing JSON objects for HTML table
Convert JSON array to an HTML table in jQuery
https://github.com/afshinm/Json-to-HTML-Table
Related
I'm trying to translate a text/paragraph from its original English version to valley girl talk. So for instance, "hi" will be "hellloooooo, what is up?". The words have been entered into a database with the English word and its translated valley girl version. Example: English column-> hi, VG column-> hellloooooo, English-> yes, VG -> like, hells yes
I am using MySQL to get the translated words off the database and returning a json.
So this is how I'm retrieving it in AJAX:
$.ajax({
type: "GET",
url: "dictionary.php",
success: function(data) {
var json = JSON.parse(data);
// replacing all the ing's with in'
$("#textarea").each(function(){
var ing = $(this).val().replace(/ing/g,"in'");
$(this).val(ing);
// finding the English words and replacing with VG
$.each(json, function(idx, obj) {
var vg= $("#content").val().replace(/obj.english/g, obj.vg);
$("#textarea").val(vg);
);
});
}
});
I got the "ing" replacements well and working but trying to replace the valley girl words is a no go. Am I looping through the json objects incorrectly?
EDIT: here is the json data
[{"english":"hi","0":"hi","vg":"hellloooooo!","1":"hellloooooo"}, {"english":"yes","0":"yes","vg":"like, hells yes","1":"like, hells yes"},.....]
please see this small example of replacing the words, then outputting this to a new field, this may help with what you want to achieve.
it loops over each word and goes for an exact word match, you may run into issues if some of the translations also contain words in english
$(document).ready(function(){
var json = [{"english":"hi","0":"hi","vg":"hellloooooo!","1":"hellloooooo"}, {"english":"yes","0":"yes","vg":"like, hells yes","1":"like, hells yes"}];
var userInput = $('#textarea').val();
json.forEach(function(word){
console.log(word);
userInput = userInput.replace(new RegExp("\\b"+word.english+"\\b","g"),word.vg);
});
$('#translation').val(userInput);
});
<!DOCTYPE html>
<html>
<head>
<script src="https://code.jquery.com/jquery-2.1.4.js"></script>
<meta charset="utf-8">
<meta name="viewport" content="width=device-width">
<title>JS Bin</title>
</head>
<body>
<textarea id="textarea">
hi this is a test of yes translation. hi yes
</textarea>
<textarea id="translation">
</textarea>
</body>
</html>
Your code seems to have several logical mistakes. You're looping over a jQuery selection where an id is used? An id is always treated as unique regardless of what you do, hence it's called id :) Then you're replacing the value of the html element every time (which just happens to be once in this case but that's a mistake on your part I assume).
I changed your html a bit so that your code will work correctly.
HTML:
<textarea class="text">
hi this is a text area what is going on? hi how are you? yes, I am fine.
</textarea>
<textarea class="text">
hi this is a text area what is going on? hi how are you? yes, I am fine.
</textarea>
JavaScript/JQuery:
$.ajax({
url: "dictionary.php",
type:"GET",
success: function(data) {
//store the parsed json
var json = JSON.parse(data);
//loop through the .text elements
$(".text").each(function(){//begin outer each
//reference the current object
var that = $(this);
//replace the all of the ing's with in'
var ing = $(this).val().replace(/ing/g,"in'");
$(this).val(ing);
// finding the English words and replacing with VG
$.each(json, function(idx, obj) {//begin inner each
//Create a new regular expression that matches the word only.
var regExp = new RegExp("\\b" + obj.english,"g");
//Replace the value of the text value with the vg value and store it.
var vg = that.val().replace(regExp, obj.vg);
//Replace the value of the .text text area in the dom.
that.val(vg);
});//<-- was missing a closing } bracket. //end inner each
});//end outer each
}
});
I’m making a random sentence generator for my English class. I’m close but because of my limited php and javascript knowledge I need to ask for help. I’m not bad at reading the code, I just get stuck writing it.
I want to use explode to break up a string of comma seperated values. The string is a mix of English and Spanish, on the .txt file they would seperated like:
The book, El libro
The man, El hombre
The woman, La mujer
etc.
I would like to break these two values into an array and display them in separate places on my web page.
I`m going to use a random text generator script that I found, it’s working great with no problems. I just need to modify it using explode to read, separate the values into an array, and be able to display the separate values of the array.
<?php
/* File, where the random text/quotes are stored one per line */
$settings['text_from_file'] = 'quotes.txt';
/*
How to display the text?
0 = raw mode: print the text as it is, when using RanTex as an include
1 = Javascript mode: when using Javascript to display the quote
*/
$settings['display_type'] = 1;
/* Allow on-the-fly settings override? 0 = NO, 1 = YES */
$settings['allow_otf'] = 1;
// Override type?
if ($settings['allow_otf'] && isset($_GET['type']))
{
$type = intval($_GET['type']);
}
else
{
$type = $settings['display_type'];
}
// Get a list of all text options
if ($settings['text_from_file'])
{
$settings['quotes'] = file($settings['text_from_file']);
}
// If we have any text choose a random one, otherwise show 'No text to choose from'
if (count($settings['quotes']))
{
$txt = $settings['quotes'][array_rand($settings['quotes'])];
}
else
{
$txt = 'No text to choose from';
}
// Output the image according to the selected type
if ($type)
{
// New lines will break Javascript, remove any and replace them with <br />
$txt = nl2br(trim($txt));
$txt = str_replace(array("\n","\r"),'',$txt);
// Set the correct MIME type
header("Content-type: text/javascript");
// Print the Javascript code
echo 'document.write(\''.addslashes($txt).'\')';
}
else
{
echo $txt;
}
?>
The script that displays the result:
<script type="text/javascript" src="rantex.php?type=1"></script>
Can someone please help me modify the rantex.php file so that I can use explode to separate the different comma separated values, and use a different script to call them in different places on my web page?
Thank you, and please excuse my noobness.
The following seems unnecessary, since file() will have already removed new line characters:
// New lines will break Javascript, remove any and replace them with <br />
$txt = nl2br(trim($txt));
$txt = str_replace(array("\n","\r"),'',$txt);
To break your line, you may instead use:
list($english, $spanish) = explode(', ', trim($txt));
It seems you are trying to use PHP to serve a static page with some random sentences, right? So why not use PHP to serve valid JSON, and handle to display logic on the client?
Heres a quick implementation.
// Get the data from the text file
$source = file_get_contents('./quotes.txt', true);
// Build an array (break on every line break)
$sentences = explode("\n", $source);
// Filter out empty values (if there is any)
$filtered = array_filter($sentences, function($item) {
return $item !== "";
});
// Build a hashmap of the array
$pairs = array_map(function($item) {
return ['sentence' => $item];
}, $filtered);
// Encode the hashmap to JSON, and return this to the client.
$json = json_encode($pairs);
Now you can let the client handle the rest, with some basic JavaScript.
// Return a random sentence from your list.
var random = sentences[Math.floor(Math.random() * sentences.length)];
// Finally display it
random.sentence
[edit]
You can get the JSON data to client in many ways, but if you don't want to use something like Ajax, you could simply just dump the contents on your webpage, then use JavaScript to update the random sentence, from the global window object.
// Inside your php page
<p>English: <span id="english"></span></p>
<p>Spanish: <span id="spanish"></span></p>
<script>
var sentences = <?= json_encode($pairs); ?>;
var random = sentences[Math.floor(Math.random() * sentences.length)];
var elspa = document.getElementById('spanish');
var eleng = document.getElementById('english');
elspa.innerText = random.sentence.split(',')[1];
eleng.innerText = random.sentence.split(',')[0];
</script>
Ok, so I have this figured out, I take 0 credit because I paid someone to do it. Special thanks to #stormpat for sending me in the right direction, if not for him I wouldn't have looked at this from a JSON point of view.
The .PHP file is like so:
<?php
$f_contents = file('quotes.txt');
$line = trim($f_contents[rand(0, count($f_contents) - 1)]);
$data = explode(',', $line);
$data['eng'] = $data[0];
$data['esp'] = $data[1];
echo json_encode($data);
?>
On the .HTML page in the header:
<script src="https://ajax.googleapis.com/ajax/libs/jquery/1.11.2/jquery.min.js"></script>
<script>
(function ($) {
$(function()
{
function load_random_data() {
$.get('random_line.php', function(data) {
var data = $.parseJSON(data);
$('#random_english').text(data.eng);
$('#random_spanish').text(data.esp);
});
}
load_random_data();
$('#get_random').click(function(e){
e.preventDefault();
load_random_data();
});
});
})(jQuery);
</script>
This splits the different variables into classes, so to call them into my html page I call them by their class, for instance I wanted to drop the variable into a table cell so I gave the individual td cell a class:
<td id="random_spanish"></td>
<td id="random_english"></td>
Plus as a bonus the coder threw in a nifty button to refresh the json classes:
<input type="button" value="Get random" id="get_random" />
So now I don`t have to have my students refresh the whole web page, they can just hit the button and refresh the random variables.
Thanks again everyone!
I'm using JavaScript to access the HTML table element.
<html>
<head>
<title>Popup page</title>
</head>
<body>
<form name="F1" method="POST">
TOTAL : <p id="total"></p>
PERCENTAGE : <p id="percentage"></p>
</form>
//This table has 9 rows and 7 columns.
// I'd like to get the 6th column elements from 2nd row onwards.
<table class="collapse" >
<tbody>
<tr><td>S.No.</td><td>Subject Code</td><td>Subject Name </td><td>Int. Marks</td>
<td>Ext. Marks</td><td>Total</td><td>Credits</td><td>Result</td></tr>
<tr><td>1</td><td>GR11A1009</td><td>Environmental Science</td><td>23</td><td>66</td>
<td>89</td><td>3</td><td>P</td></tr>
<tr><td>2</td><td>GR11A1010</td><td>Mathematics - II</td><td>22</td><td>58</td>
<td>4</td><td>P</td></tr><td>80</td>
<tr><td>3</td><td>GR11A1011</td><td>Engineering Chemistry</td><td>17</td><td>53</td>
<td>70</td><td>3</td><td>P</td></tr>
<tr><td>4</td><td>GR11A1012</td><td>Engineering Graphics</td><td>20</td><td>47</td>
<td>67</td><td>3</td><td>P</td></tr>
<tr><td>5</td><td>GR11A1013</td><td>IT Workshop</td><td>25</td><td>43</td><td>68</td>
<td>2</td><td>P</td></tr>
<tr><td>6</td><td>GR11A1014</td><td>Engineering Chemistry Lab</td><td>13</td>
<td>30</td><td>43</td><td>3</td><td>P</td></tr>
<tr><td>7</td><td>GR11A1015</td><td>English Lab</td><td>20</td><td>44</td><td>64</td>
<td>3</td><td>P</td></tr>
<tr><td>8</td><td>GR11A1018</td><td>Mathematics - III</td><td>20</td><td>67</td>
<td>3</td><td>P</td></tr>
</tbody>
</table>
//JavaScript starts here
<script>
var table = document.getElementByClass("collapse");
var marks = new Array();
var total = 0,percentage;
//here is code to get all the 6th column elements fro 2nd row onwards.
for(var i=0;i<8;i++)
marks[i] = table.ChildNodes[0].ChildNodes[i+1].ChildNodes[5].nodeValue;
//here I'm adding all the values stored ( subject marks) and finding the grand total
for(var i=0;i<8;i++)
total +=marks[i];
//now, I'm calculating the percentage
percentage = total/725;
//Below code isn't having any effect. Why is it?
document.getElementById("total").innerHTML = total;
document.getElementById("percentage").innerHTML = percentage;
</script>
</body>
</html>
What is the problem with the above code ? What can I do to solve it?
Here is the output:
There are several problems with the code. In addition to the problem with getElementByClass (there is no such method, use document.getElementsByClassName("collapse")[0] instead), you are trying to access the elements in the table using ChildNodes (undefined). You probably meant to write childNodes, but you should really using children, since you don’t want to have to do with all the text nodes containing just whitespace. And you are accessing cells without checking that they exist; not all rows have 6th cell in your table.
There is also a spurious </tr> tag that confuses table parsing. Remove it.
Morever, to get the content of a td element, you cannot use nodeValue, which is defined for text nodes only. You could use innerText, but due to issues in browser support, the good old innerHTML is safer. Then you need to convert the data from string to number (otherwise adding 2 and 2 gives your 22, not 4), e.g. with the Number function. You may wish to add some error-checking here (and elsewhere).
for(var i=0;i<8;i++)
marks[i] = table.children[0].children[i+1].children[5].innerHTML;
for(var i=0;i<8;i++)
total += Number(marks[i]);
I think you mean document.getElementsByClassName()
change your document.getElementByClass to document.getElementsByClassName()
And my personal suggestion for you is to use jquery for this , which may be much more efficient and easy for this purpose
In jquery you can simplify it like this
(Dont forget to add a class to your total TD)
var total = 0;
var percentage = 0;
$(".collapse tr").each(function(e){
var tr = $(this);
var mark =$(this).find(".total").html();
var marktst=0;
if(!isNaN(Number(mark))) //NullChecking
{
marktst =Number(mark);
}
total +=marktst;
});
document.getElementById("total").innerHTML = total;
A fiddle is given below
http://jsfiddle.net/AmarnathRShenoy/j4hVc/5/
I have a list of airport codes, names, and locations in an Excel Spreadsheet like the below:
+-------+----------------------------------------+-------------------+
| Code | Airport Name | Location |
+-------+----------------------------------------+-------------------+
| AUA | Queen Beatrix International Airport | Oranjestad, Aruba|
+-------+----------------------------------------+-------------------+
My Javascript is passed a 3 character string that should be an airline code. When that happens I need to find the code on the spreadsheet and return the Airport Name and Location.
Im thinking something like:
var code = "AUA";
console.log(getAirportInfo(code));
function getAirportInfo(code) {
// get information from spreadsheet
//format info (no help needed there)
return airportInfo;
}
Where the log would write out:
Oranjestad, Aruba (AUA): Queen Beatrix International Airport
What is the easiest method to get the data I need from the spreadsheet?
Extra Info:
The spreadsheet has over 17,000 entries
The function alluded to above may be called up to 8 times in row
I don't have to use an Excel Spreadsheet thats just what I have now
I will never need to edit the spreadsheet with my code
I did search around the web but everything I could find was much more complicated than what Im trying to do so it made it hard to understand what Im looking for.
Thank you for any help pointing me in the right direction.
I ended up using a tool at shancarter.com/data_converter to convert my flie to a JSON file and linked that to my page. Now I just loop through that JSON object to get what I need. This seemed like the simplest way for my particular needs.
I've used a plain text file(csv, or tsv both of which can be exported directly from Excel)
Loaded that into a string var via xmlhttprequest. Usually the browsers cache will stop having to download the file on each page load.
Then have a Regex parse out the values as needed.
All without using any third party....I can dig the code out if you wish.
Example:
you will need to have the data.txt file in the same web folder as this page, or update the paths...
<html>
<head>
<script>
var fileName = "data.txt";
var data = "";
req = new XMLHttpRequest();
req.open("GET", fileName, false);
req.addEventListener("readystatechange", function (e) {
data = req.responseText ;
});
req.send();
function getInfoByCode(c){
if( data == "" ){
return 'DataNotReady' ;
} else {
var rx = new RegExp( "^(" + c + ")\\s+\\|\\s+(.+)\\s+\\|\\s+\\s+(.+)\\|", 'm' ) ;
var values = data.match(rx,'m');
return { airport:values[2] , city:values[3] };
}
}
function clickButton(){
var e = document.getElementById("code");
var ret = getInfoByCode(e.value);
var res = document.getElementById("res");
res.innerText = "Airport:" + ret.airport + " in " + ret.city;
}
</script>
</head>
<body>
<input id="code" value="AUA">
<button onclick="clickButton();">Find</button>
<div id="res">
</div>
</body>
</html>
I am having a lot of trouble learning RegExp and coming up with a good algorithm to do this. I have this string of HTML that I need to parse. Note that when I am parsing it, it is still a string object and not yet HTML on the browser as I need to parse it before it gets there. The HTML looks like this:
<html>
<head>
<title>Geoserver GetFeatureInfo output</title>
</head>
<style type="text/css">
table.featureInfo, table.featureInfo td, table.featureInfo th {
border:1px solid #ddd;
border-collapse:collapse;
margin:0;
padding:0;
font-size: 90%;
padding:.2em .1em;
}
table.featureInfo th {
padding:.2em .2em;
font-weight:bold;
background:#eee;
}
table.featureInfo td{
background:#fff;
}
table.featureInfo tr.odd td{
background:#eee;
}
table.featureInfo caption{
text-align:left;
font-size:100%;
font-weight:bold;
text-transform:uppercase;
padding:.2em .2em;
}
</style>
<body>
<table class="featureInfo2">
<tr>
<th class="dataLayer" colspan="5">Tibetan Villages</th>
</tr>
<!-- EOF Data Layer -->
<tr class="dataHeaders">
<th>ID</th>
<th>Latitude</th>
<th>Longitude</th>
<th>Place Name</th>
<th>English Translation</th>
</tr>
<!-- EOF Data Headers -->
<!-- Data -->
<tr>
<!-- Feature Info Data -->
<td>3394</td>
<td>29.1</td>
<td>93.15</td>
<td>བསྡམས་གྲོང་ཚོ།</td>
<td>Dam Drongtso </td>
</tr>
<!-- EOF Feature Info Data -->
<!-- End Data -->
</table>
<br/>
</body>
</html>
and I need to get it like this:
3394,
29.1,
93.15,
བསྡམས་གྲོང་ཚོ།,
Dam Drongtso
Basically an array...even better if it matches according to its field headers and from which table they are somehow, which look like this:
Tibetan Villages
ID
Latitude
Longitude
Place Name
English Translation
Finding out JavaScript does not support wonderful mapping was a bummer and I have what I want working already. However it is VERY VERY hard coded and I'm thinking I should probably use RegExp to handle this better. Unfortunately I am having a real tough time :(. Here is my function to parse my string (very ugly IMO):
function parseHTML(html){
//Getting the layer name
alert(html);
//Lousy attempt at RegExp
var somestring = html.replace('/m//\<html\>+\<body\>//m/',' ');
alert(somestring);
var startPos = html.indexOf('<th class="dataLayer" colspan="5">');
var length = ('<th class="dataLayer" colspan="5">').length;
var endPos = html.indexOf('</th></tr><!-- EOF Data Layer -->');
var dataLayer = html.substring(startPos + length, endPos);
//Getting the data headers
startPos = html.indexOf('<tr class="dataHeaders">');
length = ('<tr class="dataHeaders">').length;
endPos = html.indexOf('</tr><!-- EOF Data Headers -->');
var newString = html.substring(startPos + length, endPos);
newString = newString.replace(/<th>/g, '');
newString = newString.substring(0, newString.lastIndexOf('</th>'));
var featureInfoHeaders = new Array();
featureInfoHeaders = newString.split('</th>');
//Getting the data
startPos = html.indexOf('<!-- Data -->');
length = ('<!-- Data -->').length;
endPos = html.indexOf('<!-- End Data -->');
newString = html.substring(startPos + length, endPos);
newString = newString.substring(0, newString.lastIndexOf('</tr><!-- EOF Feature Info Data -->'));
var featureInfoData = new Array();
featureInfoData = newString.split('</tr><!-- EOF Feature Info Data -->');
for(var s = 0; s < featureInfoData.length; s++){
startPos = featureInfoData[s].indexOf('<!-- Feature Info Data -->');
length = ('<!-- Feature Info Data -->').length;
endPos = featureInfoData[s].lastIndexOf('</td>');
featureInfoData[s] = featureInfoData[s].substring(startPos + length, endPos);
featureInfoData[s] = featureInfoData[s].replace(/<td>/g, '');
featureInfoData[s] = featureInfoData[s].split('</td>');
}//end for
alert(featureInfoData);
//Put all the feature info in one array
var featureInfo = new Array();
var len = featureInfoData.length;
for(var j = 0; j < len; j++){
featureInfo[j] = new Object();
featureInfo[j].id = featureInfoData[j][0];
featureInfo[j].latitude = featureInfoData[j][1];
featureInfo[j].longitude = featureInfoData[j][2];
featureInfo[j].placeName = featureInfoData[j][3];
featureInfo[j].translation = featureInfoData[j][4];
}//end for
//This can be ignored for now...
var string = redesignHTML(featureInfoHeaders, featureInfo);
return string;
}//end parseHTML
So as you can see if the content in that string ever changes, my code will be horribly broken. I want to avoid that as much as possible and try to write better code. I appreciate all the help and advice you can give me.
Do the following steps:
Create a new documentFragment
Put your HTML string in it
Use selectors to get what you want
Why do all the parsing work - which won't work anyways, since HTML is not parsable via RegExp - when you have the best HTML parser available? (the Browser)
You can use jQuery to easily traverse the DOM and create an object with the structure automatically.
var $dom = $('<html>').html(the_html_string_variable_goes_here);
var featureInfo = {};
$('table:has(.dataLayer)', $dom).each(function(){
var $tbl = $(this);
var section = $tbl.find('.dataLayer').text();
var obj = [];
var $structure = $tbl.find('.dataHeaders');
var structure = $structure.find('th').map(function(){return $(this).text().toLowerCase();});
var $datarows= $structure.nextAll('tr');
$datarows.each(function(i){
obj[i] = {};
$(this).find('td').each(function(index,element){
obj[i][structure[index]] = $(element).text();
});
});
featureInfo[section] = obj;
});
Working Demo
The code can work with multiple tables with different structures inside.. and also multiple data rows inside each table..
The featureInfo will hold the final structure and data, and can be accessed like
alert( featureInfo['Tibetan Villages'][0]['English Translation'] );
or
alert( featureInfo['Tibetan Villages'][0].id );
The "correct" way to do it is with DOMParser. Do it like this:
var parsed=new DOMParser.parseFromString(htmlString,'text/html');
Or, if you're worried about browser compatibility, use the polyfill on the MDN documentation:
/*
* DOMParser HTML extension
* 2012-09-04
*
* By Eli Grey, http://eligrey.com
* Public domain.
* NO WARRANTY EXPRESSED OR IMPLIED. USE AT YOUR OWN RISK.
*/
/*! #source https://gist.github.com/1129031 */
/*global document, DOMParser*/
(function(DOMParser) {
"use strict";
var
DOMParser_proto = DOMParser.prototype
, real_parseFromString = DOMParser_proto.parseFromString
;
// Firefox/Opera/IE throw errors on unsupported types
try {
// WebKit returns null on unsupported types
if ((new DOMParser).parseFromString("", "text/html")) {
// text/html parsing is natively supported
return;
}
} catch (ex) {}
DOMParser_proto.parseFromString = function(markup, type) {
if (/^\s*text\/html\s*(?:;|$)/i.test(type)) {
var
doc = document.implementation.createHTMLDocument("")
;
if (markup.toLowerCase().indexOf('<!doctype') > -1) {
doc.documentElement.innerHTML = markup;
}
else {
doc.body.innerHTML = markup;
}
return doc;
} else {
return real_parseFromString.apply(this, arguments);
}
};
}(DOMParser));
Change server-side code if you can (add JSON)
If you're the one that generates the resulting HTML on the server side you could as well generate a JSON there and pass it inside the HTML with the content. You wouldn't have to parse anything on the client side and all data would be immediately available to your client scripts.
You could easily put JSON in table element as a data attribute value:
<table class="featureInfo2" data-json="{ID:3394, Latitude:29.1, Longitude:93.15, PlaceName:'བསྡམས་གྲོང་ཚོ།', Translation:'Dam Drongtso'}">
...
</table>
Or you could add data attributes to TDs that contain data and parse only those using jQuery selectors and generating Javascript object out of them. No need for RegExp parsing.
Use John Resig's* pure javascript html parser
See demo here
*John Resig is the creator of jQuery
I had a similar requirement and not being that experienced with JavaScript I let jquery handle it for me with parseHTML and using find. In my case I was looking for divs with a particular class name.
function findElementsInHtmlString(document, htmlString, query) {
var domArray = $.parseHTML(htmlString, document),
dom = $();
// create the dom collection from the array
$.each(domArray, function(i, o) {
dom = dom.add(o);
}
// return a collection of elements that match the query
return dom.find(query);
}
var elementsWithClassBuild = findElementsInHtmlString(document, htmlString, '.build');