2016-06-09 71 views
1

我想將嵌套程度不高的有效HTML轉換爲具有更多受限制規則的另一個HTML。在Haskell中轉換HTML

僅下列標籤支持HTML結果:

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

嵌套的標籤是不允許的。

對於其餘的標籤及其組合,我必須創建一些規則來處理每個標籤。 所以我要像轉換:因爲<code>嵌套在<a>

<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>

例如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> 

任何建議來解決,該方法是什麼?

回答

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 
+2

感謝向我們展示你發現了什麼。 – ErikR