Created
March 26, 2015 02:56
-
-
Save lululau/4ed7c56300ae26382129 to your computer and use it in GitHub Desktop.
A ruby class to extract h1/h2/h3/... headings from HTML
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| #!/usr/bin/env ruby | |
| class HTMLHeadingParser | |
| class TreeNode | |
| attr_accessor :content, :children, :parent, :level | |
| def initialize(content, parent=nil) | |
| @content = content | |
| @children = [] | |
| self.parent = parent | |
| end | |
| def parent=(p) | |
| @parent = p | |
| @level = (parent.level + 1) rescue 0 | |
| end | |
| def to_s(indent=4) | |
| " " * (indent * @level) + content + "\n" + @children.map { |c| c.to_s(indent) } * "" | |
| end | |
| def ancestor(deepth=-1) | |
| ancst = self | |
| (deepth+1).times { ancst = ancst.parent } | |
| ancst | |
| end | |
| end | |
| class HTMLHeading | |
| attr_accessor :content, :text, :level | |
| def initialize(content, level) | |
| @content = content | |
| @level = level.to_i | |
| parse_content(content) | |
| end | |
| def content=(content) | |
| @content = content | |
| parse_content(content) | |
| end | |
| def parse_content(content) | |
| regex = %r{>?([^><]*)(</)?} | |
| @text = content.scan(regex).map(&:first).join | |
| end | |
| def to_str | |
| text | |
| end | |
| end | |
| def extract_headings(html) | |
| regex = %r{<h([1-6])[^>]*>(.*?)</h\1>} | |
| html.scan(regex).map do |(level, content)| | |
| HTMLHeading.new(content, level) | |
| end | |
| end | |
| def parse(html) | |
| root = TreeNode.new("") | |
| previous = root | |
| headings = extract_headings(html) | |
| headings.each do |heading| | |
| deepth = previous.level - heading.level | |
| next if deepth < -1 | |
| parent = previous.ancestor(deepth) | |
| this_node = TreeNode.new(heading, parent) | |
| previous.ancestor(deepth).children << this_node | |
| previous = this_node | |
| end | |
| root | |
| end | |
| end | |
| if __FILE__ == $0 | |
| html = File.read(ARGV[0]).gsub("\n", " ") | |
| puts HTMLHeadingParser.new.parse(html) | |
| end |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment