Populating an HTML table from an external XML - javascript

I have come across a problem while fetching data from an external XML document with JS. I have been following the w3schools tutorial for AJAX XML so far, but I ran into something I couldn't solve. I have a XML that looks like this:
<root>
<document-id>
<author>Tom Riddle</autor>
<title>abzy</title>
<year>1995</year>
</document-id>
<document-id>
<author>Tom Riddle</autor>
<title>abzy</title>
</document-id>
<document-id>
<author>Tom Riddle</autor>
<year>1995</year>
</document-id>
</root>
I want to dynamically access the data inside the XML and create a table while doing so. It works fine for the one DOM Element all documents share, but it gives me an error as soon as I include year or title. I guess it's because the tags are empty in some parts of the tree. Is there a way to ignore empty tags and only write something in the column if there is a value inside? Thank you for your time and knowledge.
THIS IS THE ASSOCIATED HTML
<body>
<header>
<h1>Reading Data from XML Files</h1>
</header>
<main>
<button type="button" onclick="loadDoc()">Get my CD collection</button>
<table id="demo">
</table>
</main>
<script>
function loadDoc() {
const xhttp = new XMLHttpRequest();
xhttp.onload = function() {
myFunction(this);
}
xhttp.open("GET", "books.xml");
xhttp.send();
}
function myFunction(xml) {
const xmlDoc = xml.responseXML;
const x = xmlDoc.getElementsByTagName("document-id");
console.log(x)
let table="<tr><th>Author</th><th>Title</th><th>Year</th></tr>";
for (let i = 0; i <x.length; i++) {
table += "<tr><td>" +
x[i].getElementsByTagName("author")[0].childNodes[0].nodeValue +
"</td><td>" +
x[i].getElementsByTagName("title")[0].childNodes[0].nodeValue +
"</td><td>" +
x[i].getElementsByTagName("year")[0].childNodes[0].nodeValue +
"</tr>";
}
document.getElementById("demo").innerHTML = table;
}
</script>
</body>

Check for existence before you try to access the children.
function getText(node, tag) {
var elem = node.getElementsByTagName(tag);
return elem ? elem.[0].childNodes[0].nodeValue : '';
}
for (let i = 0; i <x.length; i++) {
var cells = ['author', 'title', 'year'].map(function (tag) {
return "<td>" + getText(x[i], tag) + "</td>";
}).join("");
table += "<tr>" + cells + "</tr>");
}

try this with in line solution to check if tag exist in xml
function myFunction(xml) {
const xmlDoc = xml.responseXML;
const x = xmlDoc.getElementsByTagName("document-id");
console.log(x)
let table="<tr><th>Author</th><th>Title</th><th>Year</th></tr>";
for (let i = 0; i <x.length; i++) {
table += "<tr><td>" +
x[i].getElementsByTagName("author")[0].childNodes[0].nodeValue +
"</td><td>" + ((x[i].getElementsByTagName("title")[0] == undefined)?"": x[i].getElementsByTagName("title")[0].childNodes[0].nodeValue ) +
"</td><td>" +
((x[i].getElementsByTagName("year")[0] == undefined)?"": x[i].getElementsByTagName("year")[0].childNodes[0].nodeValue ) +
"</tr>";
}
document.getElementById("demo").innerHTML = table;
}

Related

How to parse XML using AJAX in html?

I'm trying to parse XML by using AJAX. However there were a few errors which i got saying my "html is not defined"
Basically what I want to do is to parse a specific amount of data from my XML codes and display it using HTML webpage .
The below is the list of bugs in console when I tried to run the script
at displayCountrylist (test2.html:136)
at handleStatusSuccess (test2.html:61)
at readyStateChangeHandler (test2.html:32)
at XMLHttpRequest.xhttp.onreadystatechange (test2.html:16)
I tried to do everything to debug but still failed. Any one help please?
<html>
<script>
function makeAjaxQueryCountrylist()
{
var xhttp = new XMLHttpRequest();
xhttp.onreadystatechange = function()
{
readyStateChangeHandler(xhttp);
};
xhttp.open("GET", "A3_CtryData_dtd_Sample.xml", true);
xhttp.send();
}
function readyStateChangeHandler(xhttp)
{
if (xhttp.readyState == 4)
{
if(xhttp.status == 200)
{
handleStatusSuccess(xhttp);
}else
{
handleStatusFailure(xhttp);
}
}
}
function handleStatusFailure(xhttp){
var displayDiv = document.getElementById("display");
displayDiv.innerHTML = "XMLHttpRequest failed: status " + xhttp.status;
}
function handleStatusSuccess(xhttp)
{
var xml = xhttp.responseXML;
var countrylistObj = parseXMLCountrylist(xml);
displayCountrylist(countrylistObj);
}
function parseXMLCountrylist(xml)
{
var countrylistObj = {};
var countrylistElement = xml.getElementsByTagName("CountryList")[0];
var recordElementList = countrylistElement.getElementsByTagName("CountryRecord");
countrylistObj.recordList = parseRecordElementList(recordElementList);
return countrylistObj;
}
function parseRecordElementList(recordElementList)
{
var recordList = [];
for(var i=0; i < recordElementList.length; i++)
{
var recordElement = recordElementList[i];
var recordObj = parseRecordElement(recordElement);
recordList.push(recordObj);
}
return recordList;
}
function parseRecordElement(recordElement)
{
var recordObj = {};
var countrycodeElement = recordElement.getElementsByTagName("country-code")[0];
recordObj.countrycode = Number(countrycodeElement.textContent);
var nameElement = recordElement.getElementsByTagName("name")[0];
recordObj.name = nameElement.textContent;
var alpha2Element = recordElement.getElementsByTagName("alpha-2")[0];
recordObj.alpha2 = alpha2Element.textContent;
var alpha3Element = recordElement.getElementsByTagName("alpha-3")[0];
recordObj.alpha3 = alpha3Element.textContent;
var capitalcityElement = recordElement.getElementsByTagName("capital-city")[0];
recordObj.capitalcity = capitalcityElement.textContent;
return recordObj;
}
function displayCountrylist(countrylistObj)
{
for(var i=0; i < countrylistObj.recordList.length; i++)
{
var recordObj = countrylistObj.recordList[i];
html += "country-code: " + recordObj.countrycode;
html += "<br />";
html += "name: " + recordObj.name;
html += "<br />";
html += "alpha-2: " + recordObj.alpha2;
html += "<br />";
html += "alpha-3: " + recordObj.alpha3;
html += "<br />";
html += "capital-city: " + recordObj.capitalcity;
html += "<br />";
}
var displayDiv = document.getElementById("display1");
displayDiv.innerHTML = html;
}
</script>
<body>
<button onClick="makeAjaxQueryCountrylist()"> Region Info I (Format: region-fmt-1.xsl)</button>
<br /><br />
<div id="display1">
</div>
</body>
</html>
There isn't any problem with my XML codes so it has to be some error from here.
You got that error html is not defined because you are using html variable without declaring it. So, before the line
html += "country-code: " + recordObj.countrycode;
you have to write
let html = '';

Why did I get undefined values when trying to read xml file?

I am trying to read data from a xml file and display them in my html file, but when I am trying to display my values I get "undefined" values for all the values.
I am a really new with ajax and xml so excuse my code if its horrible! I will appreciate if someone got a really briefly answer.
Here's my xml file:
<gesmes:Envelope xmlns:gesmes="http://www.gesmes.org/xml/2002-08-01" xmlns="http://www.ecb.int/vocabulary/2002-08-01/eurofxref">
<gesmes:subject>Reference rates</gesmes:subject>
<gesmes:Sender>
<gesmes:name>European Central Bank</gesmes:name>
</gesmes:Sender>
<Cube>
<Cube time="2019-01-25">
<Cube currency="USD" rate="1.1346"/>
<Cube currency="JPY" rate="124.72"/>
<Cube currency="BGN" rate="1.9558"/>
<Cube currency="CZK" rate="25.697"/>
<Cube currency="DKK" rate="7.4664"/>
<Cube currency="GBP" rate="0.86580"/>
....
My javascript code:
function loadDoc() {
var xhttp = new XMLHttpRequest();
xhttp.onreadystatechange = function() {
if (this.readyState == 4 && this.status == 200) {
returndata(this);
}
};
xhttp.open("GET", "rates.xml", true);
xhttp.send();
}
function returndata(xml) {
var i;
var xmlDoc = xml.responseXML;
var table="<tr><th>currency</th><th>rates</th></tr>";
var x = xmlDoc.getElementsByTagName("Cube");
for (i = 0; i <x.length; i++) {
table += "<tr><td>" +
x[i].getElementsByTagName("currency")[0] +
"</td><td>" +
x[i].getElementsByTagName("rate")[0] +
"</td></tr>";
}
document.getElementById("demo").innerHTML = table;
}
When I click the button I got the following result:
currency rates
undefined undefined
undefined undefined
undefined undefined
undefined undefined
.....
UPDATE Javascript code(fixed):
function returndata(xml) {
var i;
var xmlDoc = xml.responseXML;
var table="<tr><th>currency</th><th>rates</th></tr>";
var x = xmlDoc.getElementsByTagName("Cube");
for (i = 2; i <x.length; i++) {
table += "<tr><td>" +
x[i].getAttribute("currency") +
"</td><td>" +
x[i].getAttribute("rate") +
"</td></tr>";
}
document.getElementById("demo").innerHTML = table;
}
Okay now it works, thank you very much, i started my variable from the value 2 because when i am trying to have a while loop like (x!=null) my webpage it still loading forever and then breaks down..
i tried that one:
function returndata(xml) {
var i;
var xmlDoc = xml.responseXML;
var table="<tr><th>currency</th><th>rates</th></tr>";
var x = xmlDoc.getElementsByTagName("Cube");
for (i = 0; i <x.length; i++) {
while (x!=null) {
table += "<tr><td>" +
x[i].getAttribute("currency") +
"</td><td>" +
x[i].getAttribute("rate") +
"</td></tr>";
}
}
document.getElementById("demo").innerHTML = table;
}

Make a href=tel: work without adding number

I have a javascript that reads a xml Phonebook, prints a table and I'd like to make each number clickable so it would launch a Phone App.
<table class="table table-striped table-dark" id="campanie"></table>
function loadXMLDoc() {
var xmlhttp = new XMLHttpRequest();
xmlhttp.onreadystatechange = function() {
if (this.readyState == 4 && this.status == 200) {
myFunction(this);
}
};
xmlhttp.open("GET", "campanie-full.xml", true);
xmlhttp.send();
}
function myFunction(xml) {
var i;
var xmlDoc = xml.responseXML;
var table="<thead class=thead-light><tr><th><h5 class=text-dark>Nr.</h5></th><th><h5 class=text-dark>Company</h5></th><th><h5 class=text-dark>Phone 1</h5></th><th><h5 class=text-dark>Phone 2</h5></th></tr></thead>";
var x = xmlDoc.getElementsByTagName("DirectoryEntry");
for (i = 0; i <x.length; i++) {
table += "<tr><td><p>" +
[i+1] + "</p></td><td><p>" +
x[i].getElementsByTagName("Name")[0].childNodes[0].nodeValue +
"</p></td><td><a href=tel:>" +
x[i].getElementsByTagName("Telephone")[0].childNodes[0].nodeValue +
"</a></td><td><a href=tel:>" +
x[i].getElementsByTagName("Telephone")[0].childNodes[0].nodeValue +
"</a></td></tr>";
}
document.getElementById("campanie").innerHTML = table;
}
What should I do in order to have each a href=tel: work properly?
Also, you will see that I put the "Telephone" tag twice, as the Phonebook has more than one phonenumber. As a second question, I'd like to know how to make it read correctly, as the XML file can't be edited in any way. The <Telephone> tag from XML can't be changed to <Telephone1> or <Telephone2>. This question can wait, however.
EDIT: I have added an example XML
<CiscoIPPhoneDirectory>
<DirectoryEntry>
<Name>Doctor Dolittle</Name>
<Telephone>100</Telephone>
<Telephone>+19001234567</Telephone>
</DirectoryEntry>
<DirectoryEntry>
<Name>Tommy Stubbins</Name>
<Telephone>101</Telephone>
</DirectoryEntry>
<DirectoryEntry>
<Name>Chee-Chee</Name>
<Telephone>102</Telephone>
</DirectoryEntry>
<DirectoryEntry>
<Name>Prince Bumpo</Name>
<Telephone>103</Telephone>
</DirectoryEntry>
<DirectoryEntry>
<Name>Polynesia</Name>
<Telephone>104</Telephone>
</DirectoryEntry>
<DirectoryEntry>
<Name>Gub-Gub</Name>
<Telephone>105</Telephone>
</DirectoryEntry>
<DirectoryEntry>
<Name>Jip</Name>
<Telephone>106</Telephone>
</DirectoryEntry>
<DirectoryEntry>
<Name>Dab-Dab</Name>
<Telephone>107</Telephone>
</DirectoryEntry>
You'll need to check the Xml to see whether there are 1 or 2 phone numbers. (You could also make it check for none, if that could ever happen, and not add a row at all). Then you add either the 2nd phone number or an empty cell, depending on what the data says.
Change the function that creates the table contents from the Xml response, like this...
function myFunction(xml) {
var i;
var xmlDoc = xml.responseXML;
var table="<thead class=thead-light>" +
"<tr><th><h5 class=text-dark>Nr.</h5></th>" +
"<th><h5 class=text-dark>Company</h5></th>" +
"<th><h5 class=text-dark>Phone 1</h5></th>" +
"<th><h5 class=text-dark>Phone 2</h5></th>" +
"</tr></thead>";
var x = xmlDoc.getElementsByTagName("DirectoryEntry");
for (i = 0; i <x.length; i++) {
var name = x[i].getElementsByTagName("Name")[0].childNodes[0].nodeValue;
var tel1 = x[i].getElementsByTagName("Telephone")[0].childNodes[0].nodeValue;
var tel2 = "";
// if there are 2 phone numbers, get the value of the 2nd one
if (x[i].getElementsByTagName("Telephone").length === 2) {
// check that it's not an empty node...
if (x[i].getElementsByTagName("Telephone")[1].childNodes) {
tel2 = x[i].getElementsByTagName("Telephone")[1].childNodes[0].nodeValue;
}
}
table += "<tr><td><p>" + [i+1] + "</p></td>" +
"<td><p>" + name + "</p></td>" +
"<td><a href='tel:" + tel1 + "'>" + tel1 + "</a></td>";
// if we don't have a 2nd phone number then add an empty cell
if (tel2 === "") {
table += "<td></td>";
}
// if we do have a 2nd phone number then add it
else {
table += "<td><a href='tel:" + tel2 + "'>" + tel2 + "</a></td>";
}
table += "</tr>";
}
document.getElementById("campanie").innerHTML = table;
}

How do I include a header in a generated table of my javascript?

I receive in my javascript a json data that it is converted to a html table.
The script is working.. but how do I include a header in my table?
Here is the code:
<script>
$(document).ready(function(){
$('#id_adv').DataTable();
$('#id_adv').on('click','.btn',function(){
var currow = $(this).closest('tr');
var result = currow.find('td:eq(1)').text();
$.get('{% url "prop_table" %}', {var1:result}, function (data_prop) {
var data = data_prop['data_prop']
var data_json = JSON.parse(data);
var html = "";
for (var i = 0; i < data_json.length; i++) {
html += "<tr><td>" + data_json[i].fields.var1 + "</td><td>" + data_json[i].fields.var2 + "</td><tr>";
}
$('#id_prop').html(html);
})
document.getElementById('total').innerHTML = result;
});
});
</script>
Slight modification to your existing code to add a header. (I've cut out your usage of eval and just kept in the relevant part to create the HTML table header)
<script>
....
var html = "";
html += "<tr><th>Header 1</th><th>Header 2</th><tr>";
for (var i = 0; i < data_json.length; i++) {
html += "<tr><td>" + data_json[i].fields.var1 + "</td><td>" + data_json[i].fields.var2 + "</td><tr>";
}
$('#id_prop').html(html);
....
</script>
This should add a header to your table.
And I agree with the comment in your question, use the built in JSON parsing. eval is just asking to be exploited.
I think that you can add the header after create the table. The createTHead() method creates an empty element and adds it to the table. I.e.:
<script>
function createHeader() {
var table = document.getElementById("myTable");
var header = table.createTHead();
var row = header.insertRow(0);
var cell = row.insertCell(0);
cell.innerHTML = "<b>This is a table header</b>";
}
</script>

Images aren't displaying from XML to HTML table

I am trying to get an image to display in the table below, the image isn't displaying instead just the URL to the image is. Below is the what I have put into the HTML file. I have copied it off another site and also do not want the push button option and I am not sure how to get rid of that.
<div id="container">
<table id="demo"></table>
<button type="button" onclick="loadXMLDoc()">Get my CD collection</button>
<br><br>
<script>
function loadXMLDoc() {
var xmlhttp = new XMLHttpRequest();
xmlhttp.onreadystatechange = function() {
if (xmlhttp.readyState == 4 && xmlhttp.status == 200) {
myFunction(xmlhttp);
}
};
xmlhttp.open("GET", "amateur.xml", true);
xmlhttp.send();
}
function myFunction(xml) {
var i;
var xmlDoc = xml.responseXML;
var img = document.createElement("img");
var table="<tr><th>Rating</th><th>Title</th><th>Thumbnail</tr>";
var x = xmlDoc.getElementsByTagName("video");
for (i = 0; i <x.length; i++) {
table += "<tr><td>" +
x[i].getElementsByTagName("rating")[0].childNodes[0].nodeValue +
"</td><td>" +
x[i].getElementsByTagName("title")[0].childNodes[0].nodeValue +
"</td><td>" +
img.src = x[i].getElementsByTagName("thumbnail")[0].childNodes[0].nodeValue
document.write(img.src);
document.body.appendChild(img)"</td></tr>";;
}
document.getElementById("demo").innerHTML = table;
}
</script>
</div>
This is a sample of what the XML file looks like, it has been edited slightly as it is inappropriate for the content to be shown. The XML file is called "amateur.xml"
<?xml version="1.0" encoding="utf-8"?>
<videos>
<video id="1fb853907b9ca6add9ac">
<url>a.com</url>
<categories>A</categories>
<rating>100</rating>
<title>A</title>
<tags>A;a;AB</tags>
<duration>15</duration>
<thumbnail>http://i1.cdn2a.image.phncdn.com/m=eGcE8daaaa/videos/201011/03/148553/original/12.jpg</thumbnail>
</video>
<video id="d95ebc6a75c00d9926e7">
<url>http://ab.com</url>
<categories>A;B;An</categories>
<rating>100</rating>
<title>Sie spritzt ab</title>
<tags>a;b;as;d</tags>
<duration>65</duration>
<thumbnail>http://i0.cdn2a.image..phncdn.com/m=eGcE8daaaa/videos/201102/17/160998/original/12.jpg</thumbnail>
</video>
</videos>
Why is there a document.write(img.src)? Normally, you use that when you put it in into an <img> tag but then you don't need to create the image object, like:
for (i = 0; i <x.length; i++) {
var img = x[i].getElementsByTagName("thumbnail")[0].childNodes[0].nodeValue;
table += "<tr><td>" +
x[i].getElementsByTagName("rating")[0].childNodes[0].nodeValue +
"</td><td>" +
x[i].getElementsByTagName("title")[0].childNodes[0].nodeValue +
"</td><td><img src='"+img+"'></td></tr>";
}

Categories