我想将一个嵌套级别不高的有效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>
有关解决方法的任何建议吗?
答案 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