美好的一天,我有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
然后结果是令人惊讶的,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驱动程序中正确提取值吗?
答案 0 :(得分:1)
一切都按预期工作 - 只有你的期望是错误的。 =)
你所看到的不是原始的String
;它们是String
,它们被show
函数转义为纯粹在可打印的ASCII范围内,由print
调用:
print = putStrLn . show
永远不要害怕:在内存中,print
作为"\1058"
的字符串实际上是一个单一的Unicode代码点。您可以通过打印您感兴趣的String
之一的长度并将其与您期望的Unicode代码点数进行比较来观察此情况。
答案 1 :(得分:1)
以下行确认aeson的编码正常工作(使用utf8-string库将惰性字节串中的utf8数据读回haskell字符串:
> putStrLn $ Data.ByteString.Lazy.UTF8.toString $ encode $ ("\1058\1080\1087 \1087\1086\1076",12)
["Тип под",12]
更仔细地查看您的代码,我看到了真正的问题。您正在调用T.pack $ show $ DB.value
- 这将呈现为文字代码点,然后将其打包到文本对象中。修复是从show切换到更智能的东西。看看这个(未经测试的)
smartShow :: DB.Value -> Text
smartShow (String s) = Data.Text.Encoding.decodeUtf8 $ Data.CompactString.UTF8.toByteString s
smartShow x = T.pack $ show x
显然要处理递归案例等,你需要比这更聪明,但这是一般概念...
事实上,“最好的”事情是直接编写BSON -> JSON
函数,而不是完全通过任何中间结构。