-
<div>
-
<ul>
-
<li> lalalalala </li>
-
<li><strong><a href="http://www.google.com"> Google
-
</a>
-
</strong>
-
</li>
-
</ul>
-
</div>
自动闭合 html 标签简化版
Chito 现在用 Rubyful Soup 来解决 html 没有正确闭合的问题,其中的 BeautifulSoup 类的 prettify 方法非常强大,几乎可以修正 html 中的所有错误。
不过 Chito 只是拿来闭合标签,其他的功能完全用不到,Rubyful Soup 还要依赖 htmltools 这个库,为了个闭合标签就要多附带这么多库太不爽了,而且还有个 %nbsp 的 bug。
自己尝试写了个,close_html:
-
def close_html(html)
-
stream = html.scan( /<\s*[^>]+>/ ).map {|x| x[ /<\s*([^>^\s]*)[^>]*>/ , 1]}
-
stack = []
-
stream.each do |x|
-
if x =~ /^\//
-
stack.pop if x[1..-1] == stack.last
-
else
-
stack.push x
-
end
-
end
-
stack.reverse.each {|x| html << "</#{x}>\n"}
-
html
-
end
处理的方式罗嗦了一些,先把 html 文本中的标签提取出来,然后再去掉属性之类的,转换成一个 “标签流”,比如:
<div class="main><ul><li>test</li>
就转换成了:
["div","ul","li""/li"]
接着读取上面这个流,把开始标签压栈,遇到以 / 开头的结束标签,检查是否和栈顶的标签相匹配,匹配就弹出,走完标签流后,还留在栈里的标签就是需要闭合的标签了。
测试一下:
-
test_html = <<END
-
<div>
-
<ul>
-
<li> lalalalala </li>
-
<li><strong><a href="http://www.google.com"> Google
-
END
-
-
puts close_html(test_html)
输出:
效果不错,标签都正确闭合了~
这种方法还是有局限性的,因为只是个简单的栈操作,所以只适合修正那些正确的 html 被拦腰截断的情况,而不能修正类似 <h1></h2> 这样匹配错误的情况,<div><a></div> 这样中间格式错误的情况也不行,不过 Chito 的编辑器和 textile 都不会生成这些样子的 html,所以完全可以用这个小函数替代那个庞大的 Rubyful Soup 了~