0

I have some HTML that is returned from a web service. I do not have control over the HTML as its not my web service. This web service returns HTML that looks like this:

<table id="result">
  <tbody>
    <tr>
      <td><b>Name</b></td>
      <td>John Smith</td>
    </tr>

    <tr>
      <td valign="top"><b>Address: </b></td>
      <td>123 Oak Street<br>Chicago, IL 12345-9023</td>
    </tr>

    <tr>
      <td><b>Phone: </b></td>
      <td>123-456-7890</td>
    </tr>

    <tr>
      <td><b>Occupation: </b></td>
      <td>Teacher</td>
    </tr>

    <tr>
      <td><b>Status: </b></td>
      <td>ACTIVE</td>
    </tr>
  </tbody>
</table>

I know that the table is basically key-value pairs. I know the left column contains a label. I know the right column has the value I'm interested in. I'm trying to get the values and put it into a JSON structure. For example,I have

var json = {
  name: '',                 // How do I reference the name value in the table?
  address: '',              // How do I reference the address value in the table?
  phone: '',               // How do I reference the phone value in the table?
  occupation: '',          // etc.
  status: ''               // etc.
}

How do I get the table values using jQuery so that I can populate my JSON? I know that my table is going to be consistently this structure.

Thanks!

4 Answers 4

2

Here is my version.

Html:

<script src="//code.jquery.com/jquery-1.12.0.min.js"></script>

<table id="result">
  <tbody>
    <tr>
      <td><b>Name</b></td>
      <td>John Smith</td>
    </tr>

    <tr>
      <td valign="top"><b>Address: </b></td>
      <td>123 Oak Street<br>Chicago, IL 12345-9023</td>
    </tr>

    <tr>
      <td><b>Phone </b></td>
      <td>123-456-7890</td>
    </tr>

    <tr>
      <td><b>Occupation </b></td>
      <td>Teacher</td>
    </tr>

    <tr>
      <td><b>Status </b></td>
      <td>ACTIVE</td>
    </tr>
  </tbody>
</table>

<br>

<p id="jsonOutput"></p>

JQuery:

var $output = $("#jsonOutput");
var $table = $("#result");
var generatedJson = {};

$table.find("tr").each(function(){
    //iterate each row

  var $row = $(this);
  var jsonPropertyName = $row.find("td:nth-child(1)").text().trim();
    var jsonPropertyValue = $row.find("td:nth-child(2)").text().trim();

  generatedJson[jsonPropertyName] = jsonPropertyValue;

});


$output.text(JSON.stringify(generatedJson));

Output:

{
    "Name": "John Smith",
    "Address": "123 Oak StreetChicago, IL 12345-9023",
    "Phone": "123-456-7890",
    "Occupation": "Teacher",
    "Status": "ACTIVE"
}

play in Fiddle

It is important to note that the property name should be named like a variable name. so no weird symbols or spaces. you need to do that part yourself. this example does not cover that.

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

Comments

2

If the order of the rows never change, you can access the content this way :

var result = $('#result'),
    json = {
        name: result.find('tr:first > td:last').text(),
        address: result.find('tr:eq(1) > td:last').text(),
        phone: result.find('tr:eq(2) > td:last').text(),
        occupation: result.find('tr:eq(3) > td:last').text(),
        status: result.find('tr:eq(4) > td:last').text(),
    };

1 Comment

To add onto this, I would pull $('#result') out into a variable above the json object so you aren't traversing the dom multiple times to find the same object.
0

If the orders change then you can use it like this:

$(function(){
   var data = {};

   $("#result tbody").children("tr").each(function(index){
        var key = $(this).children("td").first().text().toLowerCase();
        var value = $(this).children("td").last().text();
        if(key.indexOf("name") >= 0){
            data.name = value;  
        }else if (key.indexOf("address") >= 0){
           data.address = value;
        }else if (key.indexOf("phone") >= 0){
           data.phone = value;
        }else if (key.indexOf("occupation") >= 0){
           data.occupation = value;
        }else if (key.indexOf("status") >= 0){
           data.status = value;
        }
  });
  console.log(data);
});

1 Comment

Actually, the indexes will always be equal to 0 because there is no text before. You should test if indexOf("whatever") !== -1 (indexOf returns -1 if it has not found the string)
0

I'd suggest, in plain JavaScript (assuming the table is added to your DOM):

// using ECMAScript 2015, ES6, to assign variables using 'let',
// and Array.from() to convert the collection returned from
// document.querySelectorAll() into an Array so that we can
// use Array methods:
let rows = Array.from(document.querySelectorAll('#result tr')),

  // declaring an empty object, using Object literal syntax:
  result = {};

  // iterating over the rows Array, using Array.prototype.forEach()
  rows.forEach(function(row) {
  // 'row' here is the current array-element in the Array over
  // which we're iterating, the name is user-defined.

  // finding the first child of the row element, which must be
  // a <td> element, finding that <td> element's textContent
  // and trimming leading and trailing whitespace using
  // String.prototype.trim():
    let key = row.children[0].textContent.trim(),

  // finding the second <td> child of the row element,
  // because the value may contain new-lines we use 
  // String.prototype.replace() to replace one-or-more
  // white-space characters (\s+) globally (g) from
  // the textContent and replace it with a single white-
  // space character (the second argument). We then trim()
  // that resultant string, to remove leading/trailing
  // white-space:
      value = row.children[1].textContent.replace(/\s+/g,' ').trim();

    // assigning the key, and its value, to the Object:
    result[key] = value;
  });

console.log(JSON.stringify( result ));
  // {"Name":"John Smith","Address:":"123 Oak Street Chicago, IL 12345-9023","Phone:":"123-456-7890","Occupation:":"Teacher","Status:":"ACTIVE"}

let rows = Array.from(document.querySelectorAll('#result tr')),
  result = {};
rows.forEach(function(row) {
  let key = row.children[0].textContent.trim(),
    value = row.children[1].textContent.replace(/\s+/g, ' ');

  result[key] = value;
});

console.log(JSON.stringify( result ));
<table id="result">
  <tbody>
    <tr>
      <td><b>Name</b>
      </td>
      <td>John Smith</td>
    </tr>

    <tr>
      <td valign="top"><b>Address: </b>
      </td>
      <td>123 Oak Street
        <br>Chicago, IL 12345-9023</td>
    </tr>

    <tr>
      <td><b>Phone: </b>
      </td>
      <td>123-456-7890</td>
    </tr>

    <tr>
      <td><b>Occupation: </b>
      </td>
      <td>Teacher</td>
    </tr>

    <tr>
      <td><b>Status: </b>
      </td>
      <td>ACTIVE</td>
    </tr>
  </tbody>
</table>

JS Fiddle demo.

An amendment to the above, in order to convert it to a function:

// Again, using ECMAScript 2015, ES6

function valuesToObject(opts) {
  'use strict';

  // declaring the default settings:
  let settings = {

    // the common parent of the elements
    // containing both the label and value
    // elements (this is passed to
    // document.querySelectorAll() so must
    // be a valid CSS selector):
    'labelValuesParent': 'tr',

    // the index of the label element
    // among the common parent's children:
    'labelIndex': 0,

    // the index of the value element
    // among the common parent's children:
    'valueIndex': 1
  };

  // if we have an opts Object passed in by the user/script,
  // and that Object has a 'from' property:
  if (opts && opts['from']) {

    // we iterate over the Array of Object keys from the
    // opts Object, using Array.prototype.forEach():
    Object.keys(opts).forEach(function(key) {
      // 'key' is the current array-element of the
      // array, the name is user-specified.

      // setting the key property of the settings Object
      // to the value of opts[ key ] value:
      settings[key] = opts[key];
    });

    // for no reason other than brevity, this can be omitted
    // so long as you remember to update the Object name
    // elsewhere or simply declare the initial 'settings'
    // Object with the name of 's':
    let s = settings,

      // if the s.from (which we checked existed already)
      // has a nodeType and that nodeType is 1 (therefore
      // it is an HTMLElement node) we simply assign s.from
      // to the container variable; otherwise we (naively)
      // assume it's a String, and pass it to
      // document.querySelector() to find the first/only
      // matching that selector:
      container = s.from.nodeType && s.from.nodeType === 1 ? s.from : document.querySelector(s.from),

      // from the found container we use document.querySelectorAll()
      // to retrieve the common parent-elements of the label-value
      // pairs found within the container:
      labelValues = container.querySelectorAll(s.labelValuesParent),

      // initialising an empty Object:
      result = {},

      // declaring, not initialising, two variables for use
      // within the following forEach():
      k, v;

    // converting the collection offound parent elements
    // into an Array, using Array.from(), and iterating
    // over that Array using Array.prototype.forEach():
    Array.from(labelValues).forEach(function(parent) {

      // finding the label text by finding the element
      // children of the parent, and finding its textContent
      // using the supplied index property:
      k = parent.children[s.labelIndex].textContent,

        // finding the value text by finding the element
        // children of the parent, and finding its textContent
        // using the supplied index property:
        v = parent.children[s.valueIndex].textContent;

      // setting the trimmed key value (removing leading
      // and trailing white-space) as a new key of the
      // result Object, and setting the value of that
      // property to the textContent of the value-element,
      // after replacing sequences of white-space with
      // single white-space characters, and then trimming
      // leading and trailing space using
      // String.prototype.trim():
      result[k.trim()] = v.replace(/\s+/g, ' ').trim();

    });

    // returning the JSON stringified String
    // from the result Object
    return JSON.stringify(result);

  }

  // if there was no opts.key property we simply return
  // null, because we have no way of anticipating which
  // element might contain the label-value pairs:
  return null;

}

console.log(valuesToObject({
  'from': '#result'
}));
// {"Name":"John Smith","Address:":"123 Oak Street Chicago, IL 12345-9023","Phone:":"123-456-7890","Occupation:":"Teacher","Status:":"ACTIVE"}

function valuesToObject(opts) {
  'use strict';
  let settings = {
    'labelValuesParent': 'tr',
    'labelIn': 'td',
    'valueIn': 'td',
    'labelIndex': 0,
    'valueIndex': 1
  };

  if (opts && opts['from']) {
    Object.keys(opts).forEach(function(key) {
      settings[key] = opts[key];
    });

    let s = settings,
      container = s.from.nodeType && s.from.nodeType === 1 ? s.from : document.querySelector(s.from),
      labelValues = container.querySelectorAll(s.labelValuesParent),
      result = {},
      k, v;

    Array.from(labelValues).forEach(function(parent) {
      k = parent.children[s.labelIndex].textContent,
        v = parent.children[s.valueIndex].textContent;

      result[k.trim()] = v.replace(/\s+/g, ' ').trim();

    });

    return JSON.stringify(result);

  }

  return null;

}

console.log(valuesToObject({
  'from': '#result'
}));
// {"Name":"John Smith","Address:":"123 Oak Street Chicago, IL 12345-9023","Phone:":"123-456-7890","Occupation:":"Teacher","Status:":"ACTIVE"}
<table id="result">
  <tbody>
    <tr>
      <td><b>Name</b>
      </td>
      <td>John Smith</td>
    </tr>

    <tr>
      <td valign="top"><b>Address: </b>
      </td>
      <td>123 Oak Street
        <br>Chicago, IL 12345-9023</td>
    </tr>

    <tr>
      <td><b>Phone: </b>
      </td>
      <td>123-456-7890</td>
    </tr>

    <tr>
      <td><b>Occupation: </b>
      </td>
      <td>Teacher</td>
    </tr>

    <tr>
      <td><b>Status: </b>
      </td>
      <td>ACTIVE</td>
    </tr>
  </tbody>
</table>

JS Fiddle demo.

Comments

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.