2013-12-15 120 views
1

獲取光標的內容假設有xml文件:從非標準化的XML

  <span id="assignee-val"> 

     <span class="user-hover" id="issue_summary_assignee_m" rel="m"> 
     <span class="aui-avatar aui-avatar-small"><div class="aui-avatar-inner"><img src="/secure/useravatar?size=small&amp;avatarId=10222" /></div></span> 
     This Value! 
    </span> 
</span> 

的問題是如何讓"This Value!"出這個XML的。

這是我有:(

> :m + Control.Applicative Data.ByteString.Lazy Text.HTML.DOM Text.XML.Cursor 
> Prelude.map content . (element "span" >=> "id" `attributeIs` "assignee-val" >=> child >=> element "span" >=> "class" `attributeIs` "user-hover" >=> child) . fromDocument . parseLBS <$> Data.ByteString.Lazy.readFile "xmlfile" 
[["\n   "],[],["\n   This Value!\n  "]] 
  1. 爲什麼有3個答案是什麼?查詢將定義裏面<span class="user-hover">標籤內容更準確?
  2. 如何刪除空間縮進和換行符自動符號

UPD:?換言之,問題是如何刪除所有嵌套的標籤(它不不管有多少),並獲得第一級內容只有,這是"This Value!"(和空格和換行符)。

回答

2

問題1爲什麼有3個答案?

你導航到數據秉着「用戶懸停」 span標籤的孩子....拉出不重要的東西,你的節點看起來像這樣

<span class="user-hover"> 
    <span /> 
    This Value! 
</span> 

的XML解析器看到這作爲

<span class="user-hover">[TextNode "\n "]<span />[TextNode "\n This Value!\n"]</span> 

因此,「用戶懸停」元素確實有3個孩子。

[TextNode "\n ", <span />, TextNode "\n This Value!\n"] 

然後,將「內容」應用於這些值中的每一個。由於跨度元素沒有任何內部的內容在裏面,它返回「」,你會得到:

[["\n "], [], ["\n This Value!\n"]] 

問題2 - 您如何自動刪除空間縮進和換行的符號?

根據xml規範,xml解析器必須保留空間。可能有XML遊標庫中的工具爲你分配這個空間(一些xml處理庫給你選項來打開自動後處理空白剝離),但我並不知道它。查詢後,在另一個調用中刪除空白。您可以使用Data.Text.strip函數爲您執行空白刪除。


爲了得到你想要的值,你需要在查詢更多信息....將把數據始終處於「用戶懸停」 span元素的第三位?它會始終在<span class="aui-avatar aui-avatar-small" />元素之後嗎?是否將user-hover元素中的所有內容與空白字符串連接起來?一旦你回答了這個問題,解決方案應該很明顯。


更新答案 -

您所提供的額外的信息,我可以添加更多的信息到答案。

簡短的回答是,刪除「Prelude.map內容」,並在管道中添加「> =>內容」,然後在最終輸出中再添加一個Data.Text.concat

這裏是爲什麼....

幾乎所有Text.XML.Cursor函數的形式爲a->[a],這裏的想法是每個過濾器應用於節點列表,然後CONCAT的細節結果。這非常類似於XPath中發生的情況,並且在此之後進行了明確的建模。

的好處是,我剛纔描述的模式正是數組單子是如何工作....如果要鏈接的一堆使用綁定(>>=)a->[a]功能,該管道將基本上做一個concat . map f每個階段的管道。當您將map content添加到前面時,它可以工作,但只完成了圖書館希望在完整的XPath工具中執行的一半預期工作。它提取了文本內容,但沒有連接結果。以這種方式使用時,content僅返回元素內文本節點中文本的列表。您仍然需要最後一個連字符將這些文本項目連接在一起。

當我用管道:

Data.Text.concat . (child >=> element "span" >=> "id" `attributeIs` "assignee-val" >=> child >=> element "span" >=> "class" `attributeIs` "user-hover" >=> child >=> content) . fromDocument . parseLBS <$> Data.ByteString.Lazy.readFile "file.xml" 

我得到的結果

"\n  \n  This Value!\n " 

,如果你願意,你仍然可以用剝離的Data.Text.strip最終的結果....

+0

我已經更新了這個問題,看看:) –

1

的原因有多種答案是,user-hover跨度有多個孩子:在aui-avatar跨度之前的孩子(其中只包含空格),該aui-avatar跨度,以及含有"This Value!"之一。爲了得到最後的價值,你應該看看設置你的結果的最後一個元素,而不是重寫查詢:

λ> import Control.Applicative 
λ> import qualified Data.ByteString.Lazy as L 
λ> import qualified Data.Text as T 
λ> import Text.HTML.DOM 
λ> import Text.XML.Cursor 
λ> :set -XOverloadedStrings 
λ> let assignee = element "span" >=> "id" `attributeIs` "assignee-val" 
λ> let hover = element "span" >=> "class" `attributeIs` "user-hover" 
λ> map T.strip . content . last . (assignee >=> child >=> hover >=> child) . fromDocument . parseLBS <$> L.readFile "xmlfile" 
["This Value!"] 
+0

我已經更新了這個問題('last'似乎是一個壞主意) –