0

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 &amp; 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 &amp; 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

  • Print a row for every <business> element
  • For every <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.
  • Only print the row those <business> where value of <Price> is > 10000 . if it is then less than 10000 do not print that row
  • pagination after every 10 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 enter image description here

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?

3
  • Which browsers do you target? And as you use client-side XSLT and an HTML table, what kind of pagination do you have in mind? Commented Mar 10, 2020 at 12:55
  • @MartinHonnen All the regular browser i.e Chrome, Safari, firefox, ie. Commented Mar 10, 2020 at 13:00
  • Regarding pagination I dont have anything particular in mind. Ideally To list 10 ro on each page Commented Mar 10, 2020 at 13:02

1 Answer 1

1

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 &amp; 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 &amp; 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;
}

Sign up to request clarification or add additional context in comments.

6 Comments

Thanks for the answer. Thats really helpful. As you can see in the xml code the position of the child nodes are not similar as well. for the first <business> node the fisrt child node is <advertHeader> whereas for the second <business> node <advertHeader> node is in the 3rd position. Hence in the result it can be confusing. How can I overcome that
@Bashabi That's a different question ;). In my answer the 'incomplete row-problem' is tackled. The node order may me solved by using longest and iterating through business-elements using a querySelector per node name from that
Well, it's not that difficult to keep the order, see revised code.
Thanks a lot. In your example you passed the xml code as string. Is there any way I can pass that as a link . and get the content from that link. as my xml file is too long
"Is there any way I can pass that as a link?" Not in this (stackoverflow-) context, you have to figure that one out yourself, sorry. Maybe jsFiddle (docs.jsfiddle.net/external-resources) can help
|

Your Answer

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.