Reputation: 706
This is my xml code . I want to display the contents in a html page with Javascript.
<businesses>
<business bfsId="" id="41481">
<advertHeader>Welding Supplies, Equipment and Service Business</advertHeader>
<Price>265000</Price>
<catalogueDescription>Extremely profitable (Sales £500k, GP £182k) business</catalogueDescription>
<keyfeature1>
Well established 25 year business with excellent trading record
</keyfeature1>
<keyfeature2>
Consistently high levels of turnover and profitability over last 5 years
</keyfeature2>
</business>
<business bfsId="" id="42701">
<broker bfsRef="1771" ref="003">Birmingham South, Wolverhampton & West Midlands</broker>
<tenure>freehold</tenure>
<advertHeader>Prestigious Serviced Office Business</advertHeader>
<Price>1200000</Price>
<reasonForSale>This is a genuine retirement sale.</reasonForSale>
<turnoverperiod>Annual</turnoverperiod>
<established>28</established>
<catalogueDescription>This well-located and long-established serviced office</catalogueDescription>
<underOffer>No</underOffer>
<image1>https://www.business-partnership.com/uploads/business/businessimg15977.jpg</image1>
<keyfeature1>other connections</keyfeature1>
<keyfeature2> Investment Opportunity</keyfeature2>
<keyfeature3>Over 6,000 sq.ft.</keyfeature3>
<keyfeature4>Well-maintained </keyfeature4>
<keyfeature5>In-house services & IT provided</keyfeature5>
</business>
</businesses>
This is the original xml file https://alpha.business-sale.com/bfs.xml I have just took a short portion to describe the situation.
Requirements
<business>
element <business>
pick some specific child element and print column only for those element.( Not all ). For an example in this case I only want to print the value for <advertHeader>
; <Price>
and <description>
and want to ignore other elements. <business>
where value of <Price>
is > 10000 . if it is then less than 10000 do not print that row This is the html table
<table id="MainTable"><tbody id="BodyRows"></tbody></table>
And this is the javascript code that i have tried .
window.addEventListener("load", function() {
getRows();
});
function getRows() {
var xmlhttp = new XMLHttpRequest();
xmlhttp.open("get", "2l.xml", true);
xmlhttp.onreadystatechange = function() {
if (this.readyState == 4 && this.status == 200) {
showResult(this);
}
};
xmlhttp.send(null);
}
function showResult(xmlhttp) {
var xmlDoc = xmlhttp.responseXML.documentElement;
removeWhitespace(xmlDoc);
var outputResult = document.getElementById("BodyRows");
var rowData = xmlDoc.getElementsByTagName("business");
addTableRowsFromXmlDoc(rowData,outputResult);
}
function addTableRowsFromXmlDoc(xmlNodes,tableNode) {
var theTable = tableNode.parentNode;
var newRow, newCell, i;
console.log ("Number of nodes: " + xmlNodes.length);
for (i=0; i<xmlNodes.length; i++) {
newRow = tableNode.insertRow(i);
newRow.className = (i%2) ? "OddRow" : "EvenRow";
for (j=0; j<xmlNodes[i].childNodes.length; j++) {
newCell = newRow.insertCell(newRow.cells.length);
if (xmlNodes[i].childNodes[j].firstChild) {
newCell.innerHTML = xmlNodes[i].childNodes[j].firstChild.nodeValue;
} else {
newCell.innerHTML = "-";
}
console.log("cell: " + newCell);
}
}
theTable.appendChild(tableNode);
}
function removeWhitespace(xml) {
var loopIndex;
for (loopIndex = 0; loopIndex < xml.childNodes.length; loopIndex++)
{
var currentNode = xml.childNodes[loopIndex];
if (currentNode.nodeType == 1)
{
removeWhitespace(currentNode);
}
if (!(/\S/.test(currentNode.nodeValue)) && (currentNode.nodeType == 3))
{
xml.removeChild(xml.childNodes[loopIndex--]);
}
}
}
But this code prints columns for all the nodes under <business>
element. And the number of child elements under <business>
are different . So the result comes like this
I dont want that. I want to only display the value of specific nodes under <business>
element (in this case only include <advertHeader>
; <Price>
and <description>
) so that the number of columns are equal in every row. How to do that?
Upvotes: 0
Views: 1239
Reputation: 122888
Try finding the <business>
-element with the most values and build your table around that. Here's an example snippet that does that for the data you presented.
{
const xml = new DOMParser()
.parseFromString(getData(), `text/xml`);
// the <business>-elements from xml
const businessElems = [...xml.querySelectorAll(`business`)];
// the nodeNames will be the header. While we're at it,
// we can count the number of headers (len) for later use
const headersFromXml = businessElems.map( v =>
[...v.querySelectorAll(`*`)]
.map( v => v.nodeName) )
.map( v => ( {len: v.length, headers: v} )
);
// now determine the longest header using a reducer
const businessElemWithMostNodes = headersFromXml
.reduce( (acc, v) => v.len > acc.len ? v : acc, {len: 0});
// utility to create a tablecell/header and append it to a row
const createCell = (rowToAppendTo, cellType, value) => {
const cell = document.createElement(cellType);
cell.innerHTML = value;
rowToAppendTo.appendChild(cell);
}
// utility to create a datarow and append it to a table
const createDataRow = (tableToAppendTo, businessElem) => {
const row = document.createElement(`tr`);
const rowValues = [];
// create values using the businessElemWithMostNodes order
businessElemWithMostNodes.headers
.forEach( head => {
const valueElem = businessElem.querySelector(`${head}`);
rowValues.push(valueElem ? valueElem.innerHTML : `-`);
});
rowValues.forEach( v => createCell(row, `td`, v) );
tableToAppendTo.appendChild(row);
};
// now we know enough to create the table
const table = document.createElement(`table`);
// the headerRow first
const headRow = document.createElement(`tr`);
businessElemWithMostNodes.headers.forEach( hv => createCell(headRow, `th`, hv) );
table.appendChild(headRow);
// next create and append the rows
businessElems.forEach(be => createDataRow(table, be));
// finally, append the table to document.body
document.body.appendChild(table);
// your xml string
function getData() {
return `
<businesses>
<business bfsId="" id="41481">
<advertHeader>Welding Supplies, Equipment and Service Business</advertHeader>
<Price>265000</Price>
<catalogueDescription>Extremely profitable (Sales £500k, GP £182k) business</catalogueDescription>
<keyfeature1>
Well established 25 year business with excellent trading record
</keyfeature1>
<keyfeature2>
Consistently high levels of turnover and profitability over last 5 years
</keyfeature2>
</business>
<business bfsId="" id="42701">
<broker bfsRef="1771" ref="003">Birmingham South, Wolverhampton & West Midlands</broker>
<tenure>freehold</tenure>
<advertHeader>Prestigious Serviced Office Business</advertHeader>
<Price>1200000</Price>
<reasonForSale>This is a genuine retirement sale.</reasonForSale>
<turnoverperiod>Annual</turnoverperiod>
<established>28</established>
<catalogueDescription>This well-located and long-established serviced office</catalogueDescription>
<underOffer>No</underOffer>
<image1>https://www.business-partnership.com/uploads/business/businessimg15977.jpg</image1>
<keyfeature1>other connections</keyfeature1>
<keyfeature2> Investment Opportunity</keyfeature2>
<keyfeature3>Over 6,000 sq.ft.</keyfeature3>
<keyfeature4>Well-maintained </keyfeature4>
<keyfeature5>In-house services & IT provided</keyfeature5>
</business>
</businesses>`;
}
}
body {
margin: 1rem;
font: 12px/15px normal consolas, verdana, arial;
}
.hidden {
display: none;
}
th {
background-color: black;
color: white;
border: 1px solid transparent;
padding: 2px;
text-align: left;
}
td {
border: 1px solid #c0c0c0;
padding: 2px;
vertical-align: top;
}
Upvotes: 1