2011-09-26 67 views
2

美好的一天,我都充滿了一些數據的MongoDB數據庫,我保證存儲在正確的字符集的數據,來獲取數據我用下面的代碼片段:Haskell。 MongoDB的驅動程序或埃宋字符集問題

{-# LANGUAGE OverloadedStrings #-} 
import Network.Wai 
import Network.Wai.Handler.Warp (run) 
import Data.Enumerator (Iteratee (..)) 
import Data.Either (either) 
import Control.Monad (join) 
import Data.Maybe (fromMaybe) 
import Network.HTTP.Types (statusOK, status404) 
import qualified Data.ByteString as B 
import qualified Data.ByteString.Lazy as L 
import Data.ByteString.Char8 (unpack) 
import Data.ByteString.Lazy.Char8 (pack) 
import qualified Data.Text.Lazy as T 
import Data.Text (Text(..)) 
import Control.Monad.IO.Class (liftIO, MonadIO) 
import Data.Aeson (encode) 
import qualified Data.Map as Map 
import qualified Database.MongoDB as DB 

application dbpipe req = do 
    case unpack $ rawPathInfo req of 
    "/items" -> itemsJSON dbpipe req 
    _ -> return $ responseLBS status404 [("Content-Type", "text/plain")] "404" 

indexPage :: Iteratee B.ByteString IO Response 
indexPage = do 
    page <- liftIO $ processTemplate "templates/index.html" [] 
    return $ responseLBS statusOK [("Content-Type", "text/html; charset=utf-8")] page 

processTemplate f attrs = do 
    page <- L.readFile f 
    return page 

itemsJSON :: DB.Pipe -> Request -> Iteratee B.ByteString IO Response 
itemsJSON dbpipe req = do 
    dbresult <- liftIO $ rundb dbpipe $ DB.find (DB.select [] $ tu "table") >>= DB.rest 
    let docs = either (const []) id dbresult 
-- liftIO $ L.putStrLn $ encode $ show $ map docToMap docs 
    return $ responseLBS statusOK [("Content-Type", "text/plain; charset=utf-8")] 
    (encode $ map docToMap docs) 

docToMap doc = Map.fromList $ map (\f -> (T.dropAround (== '"') $ T.pack $ show $ DB.label f, T.dropAround (== '"') $ T.pack $ show $ DB.value f)) doc 


main = do 
    pipe <- DB.runIOE $ DB.connect $ DB.host "127.0.0.1" 
    run 3000 $ application pipe 

rundb pipe act = DB.access pipe DB.master database act 

tu :: B.ByteString -> UString 
tu = DB.u . C8.unpack 

那麼結果是suprprising, DB.label效果很好,但DB.value給我本地字符一些轉義碼,所以結果是這樣的:

curl http://localhost:3000/items給出:

[{"Марка": "\1058\1080\1087 \1087\1086\1076", 
    "Model": "BD-W LG BP06LU10 Slim \1058\1080\1087 \1087\1086\1076\1082\1083\1102\1095\1077\1085\1080\1103"}, 
... 
] 

這發生在情況下,我嘗試以打印數據,並在我返回編碼爲JSON的數據時 任何想法如何正確地從MongoDB驅動程序提取值?

回答

1

下面這行證實,埃宋的編碼工作正常(使用UTF8串圖書館閱讀UTF8數據從慵懶的字節串回一個Haskell字符串:

> putStrLn $ Data.ByteString.Lazy.UTF8.toString $ encode $ ("\1058\1080\1087 \1087\1086\1076",12) 
["Тип под",12] 

看你的代碼更緊密地我看到了。真正的問題你打電話T.pack $ show $ DB.value - 這會呈現出如字面碼點,再包入那些文本對象的解決方法是從節目切換到一些更聰明看看這個(未經測試)

smartShow :: DB.Value -> Text 
smartShow (String s) = Data.Text.Encoding.decodeUtf8 $ Data.CompactString.UTF8.toByteString s 
smartShow x = T.pack $ show x 

顯然要處理遞歸的情況下,你需要比這更聰明,但這是一般概念...

事實上,「最好」的事情是直接編寫BSON -> JSON的函數,而不是通過任何中間結構。

+0

我看到你提出了正確的解決方案,但無法讓你的片段適用於我的案例,例如爲什麼String構造函數用於DB.Value類型? – Dfr

+0

@Dfr:因爲這是bson使用的構造函數的名稱,這就是'Value'的含義:http://hackage.haskell.org/packages/archive/bson/0.1.6/doc/html/Data- Bson.html – sclv

+0

我現在不打算安裝mongodb綁定,所以很抱歉沒有測試此代碼。然而,要點應該是正確的。 – sclv

1

一切都按預期工作 - 只有您的期望是錯誤的。 =)

你看到的是沒有生的String s;他們已逃到由show功能可打印的ASCII範圍純粹存在String的,由print叫:

print = putStrLn . show 

別擔心:在內存中,字符串print S作爲"\1058"事實上是一個單個Unicode碼點長。您可以通過打印您感興趣的String之一的長度並將其與您期望的Unicode碼點數進行比較來觀察。

+0

謝謝,這是很好的解釋,但我仍然不知道如何從數據庫中獲得正常的字符串。我試過DB.cast,但它也不起作用。或者也許更簡單的情況是如何將MongoDB'UString'轉換爲'Text' – Dfr

+0

我不知道,我沒有使用過這個庫。但在我看來,它看起來像上面粘貼的代碼已經轉換爲'String'就好了。問題在於調用'print'(而不是'putStrLn'或類似的),而不是在數據庫接口中。 –

+0

我的應用程序將結果傳遞給aeson的編碼,並且生成的JSON數據也填充了該代碼點,這是不可接受的。用戶只需要普通的UTF8字符串,而不是轉義碼。 – Dfr