0

How can I create a specific JSON object from some HTML?

Example

This is very well formatted HTML page (rendered from markdown). I want to create a JSON representation of the sections on the page.

So each "h2" is a title. Each h3, h4, or h5, that follows it is a subtitle

Given this HTML:

<h2><a href="#charts">Charts</a></h2>
<ul>...</ul>
<h5><a href="#third-party">Third Party</a></h5>
<ul>...</ul>
<h5><a href="#reusable-chart-frameworks">Reusable Chart Frameworks</a></h5>
<ul>...</ul>
<h2><a href="#maps">Maps</a></h2>
<h5><a href="#third-party-1">Third Party</h5>
...

Return this JSON:

[
  {
    "title": {
      "text": "Charts",
      "href": "#charts"
    }
    "subtitles": [
      {
        "text": "Third Party",
        "href": "#third-party"
      },
      {
        "text": "Reusable Chart Frameworks",
        "href": "#reusable-chart-frameworks"
      }
    ]
  },
  {
    "title": {
      "text": "Maps",
      "href": "#maps"
    },
    "subtitles": ]
      "text": "Third Party",
      "href": "#third-party-1"
    ]
  },
  ...
]

Solutions I've considered

Seems like something jQuery could help a lot with. If the items were nested it would be very easy to do $('h2').each(...) and just loop through each section, appending it to my JSON object. However there is no nesting here, just siblings. Any ideas?

Don P
  • 60,113
  • 114
  • 300
  • 432

2 Answers2

1

One other solution is to map it:

var mappedJSON = $('h2').map(function() {
  var $selfA = $(this).children('a');
  var subtiles = $(this).nextUntil('h2').filter(':header').children('a').map(function() {
    return {
      "text": $(this).text(),
      "href": $(this).attr('href')
    }
  }).get();
  return {
    "title": {
      "text": $selfA.text(),
      "href": $selfA.attr('href')
    },
    "subtitles": subtiles
  };
}).get();

console.log(mappedJSON);
$('<pre/>').appendTo($('body').empty()).text(JSON.stringify(mappedJSON, null, "\t"));
pre {
  tab-size: 2;
}
<script src="https://ajax.googleapis.com/ajax/libs/jquery/1.11.1/jquery.min.js"></script>
<h2><a href="#charts">Charts</a></h2>
<ul>...</ul>
<h5><a href="#third-party">Third Party</a></h5>
<ul>...</ul>
<h5><a href="#reusable-chart-frameworks">Reusable Chart Frameworks</a></h5>
<ul>...</ul>
<h2><a href="#maps">Maps</a></h2>
<h5><a href="#third-party-1">Third Party</h5>
A. Wolff
  • 74,033
  • 9
  • 94
  • 155
0

Here's a solution that just relies on jQuery's .nextUntil() function.

var sections = [];

var eTitles = $('article').find('h2');

$(eTitles).each(function(){
  var section = {
    "title": {
      "text": $(this).text(),
      "href": $(this).find('a').attr('href')
    },
    "subtitles": []
  }

  var eSubtitles = $(this).nextUntil('h2').filter('h3, h4, h5');

  $(eSubtitles).each(function(){
    var subtitle = {
      "text": $(this).text(),
      "href": $(this).find('a').attr('href')
    }

    section.subtitles.push(subtitle);
  });

  sections.push(section);
});
Don P
  • 60,113
  • 114
  • 300
  • 432