在Haskell中转换HTML

时间:2016-06-09 18:05:00

标签: html haskell

我想将一个嵌套级别不高的有效HTML转换为另一个限制规则的HTML。

生成的HTML中仅支持以下标记:

<b></b>, <strong></strong>, <i></i>, <em></em>, <a
href="URL"></a>, <code></code>, <pre></pre>

根本不允许使用嵌套标记。

对于其余的标签及其组合,我必须创建一些规则来处理每个标签。 所以我必须转换像:

<p>text</p>到带有换行符的简单字符串text

<b>text <a href="url">link</a> text</b>加入text link text

<a href="url">text<code> code here</code></a>进入<a href="url">text code here</a>,因为<code>嵌套在<a>内,依此类推。

例如HTML(换行仅仅是为了方便):

<p>long paragraph <a href="url">link</a> </p>
<p>another text <pre><code>my code block</code></pre> the rest of description</p>
<p><code>inline monospaced text with <a href="url">link</a></code></p>

应转化为:

long paragraph <a href="url">link</a>

another text <code>my code block</code> the rest of description

<code>inline monospaced text with link</code>

有关解决方法的任何建议吗?

1 个答案:

答案 0 :(得分:2)

经过一番调查,我发现在我看来,我找到了非常优雅的解决方案。它基于tagsoup库。该库具有Text.HTML.TagSoup.Tree模块,有助于将HTML解析为树结构。

它还包含transformTree函数,它可以完成转换。该功能的文档说:

  

此操作基于Uniplate转换功能。给定树的列表,它以自下而上的方式将函数应用于每个树。

您可以阅读更多关于Uniplate的更多信息here

这是我满意的代码:

import Text.HTML.TagSoup
import Text.HTML.TagSoup.Tree

convert = transformTree f
    where
      f (TagLeaf (TagOpen "br" _)) = [TagLeaf (TagText "\n")] -- line breaks
      f (TagLeaf (TagOpen _ _)) = [] -- ignore all tags without closing pairs
      f (TagBranch "a" attrs inner) = tagExtr "a" attrs inner -- keeps href for <a>
      f (TagBranch "p" _ inner) = inner ++ [(TagLeaf (TagText "\n"))]
      f (TagBranch "pre" _ [TagBranch "code" _ inner]) = tagExtr "pre" [] inner -- <pre><code> -> <code>
      f (TagBranch tag _ inner) = if tag `elem` allowedTags then tagExtr tag [] inner else inner
      f x = [x]

tagExtr tag attrs inner = [TagBranch tag attrs [(extractFrom inner)]]

allowedTags = ["b", "i", "a", "code", "a", "pre", "em", "strong"]

extractFrom x = TagLeaf $ TagText $ (innerText . flattenTree) x