HXT xpickle 在属性值和值构造函数之间进行(反)序列化
HXT xpickle (de)serialising between attribute values and value constructors
我正在尝试编写一个 xpickle,它将某种类型的值构造函数序列化为特定属性的 XML 属性值,并将 XML 属性值反序列化回类型。
我有以下数据:
module Main where
import Text.XML.HXT.Core
newtype Things = Things [Thing]
data Thing = Thing (Maybe Property)
data Property = A | B
someThings :: Things
someThings = Things [ Thing (Just A)
, Thing Nothing
, Thing (Just B)
]
我想将其序列化为类似的内容:
<things>
<thing property="a" />
<thing />
<thing property="b" />
</things>
这是我采用的方法:
instance XmlPickler Things where
xpickle = xpWrap ( \things -> Things things , \(Things things) -> things ) $
xpElem "things" $
xpThings
xpThings :: PU [Thing]
xpThings = xpList xpickle
instance XmlPickler Thing where
xpickle = xpElem "thing" $
xpWrap ( \p -> Thing p , \(Thing p) -> p ) $
xpProperty
xpProperty :: PU (Maybe Property)
xpProperty = xpOption $ xpAttr "property" xpPropertyValue
xpPropertyValue :: PU Property
xpPropertyValue = xpAlt tag ps
where
tag A = 1
tag B = 2
ps = [ xpTextAttr "a"
, xpTextAttr "b"
]
main :: IO ()
main = do
putStrLn $ showPickled [ withIndent yes ] someThings
return ()
此处,xpProperty
创建或读取一个 @property
属性,然后使用 xpPropertyValue
计算出该值。 xpPropertyValue
根据值的值构造函数确定值:A
给出 "a"
并且 B
给出 "b"
并且值是使用 xpTextAttr
功能。这里的问题是 xpTextAttr
是 String -> PU String
,我正试图在需要 PU Property
的地方使用它。但是我无法找到另一种生成 PU Property
值的方法,该方法依赖于 Property
值的值构造函数。
这没有正确使用 xpTextAttr
。首先,它的第一个参数应该是属性名称 "property"
,其次,它 return 是它匹配的文本。
您想 return 构造函数分别 A
或 B
。
您需要使用 xpWrap
指定 属性("a"
或 "b"
)的文本内容与那些构造函数之间的映射(双向)。我相信标签是基于 0 的,所以 0 和 1。
where
tag A = 0
tag B = 1
ps = [ xpWrap (const A,const "a") $ xpTextAttr "property"
, xpWrap (const B,const "b") $ xpTextAttr "property"
]
那么对xpAttr
的调用是错误的。老实说,我不确定 xpAttr
的用途,与限定名称有关。事实上 xpProperty
的足够代码是
xpProperty :: PU (Maybe Property)
xpProperty = xpOption $ xpPropertyValue
我正在尝试编写一个 xpickle,它将某种类型的值构造函数序列化为特定属性的 XML 属性值,并将 XML 属性值反序列化回类型。
我有以下数据:
module Main where
import Text.XML.HXT.Core
newtype Things = Things [Thing]
data Thing = Thing (Maybe Property)
data Property = A | B
someThings :: Things
someThings = Things [ Thing (Just A)
, Thing Nothing
, Thing (Just B)
]
我想将其序列化为类似的内容:
<things>
<thing property="a" />
<thing />
<thing property="b" />
</things>
这是我采用的方法:
instance XmlPickler Things where
xpickle = xpWrap ( \things -> Things things , \(Things things) -> things ) $
xpElem "things" $
xpThings
xpThings :: PU [Thing]
xpThings = xpList xpickle
instance XmlPickler Thing where
xpickle = xpElem "thing" $
xpWrap ( \p -> Thing p , \(Thing p) -> p ) $
xpProperty
xpProperty :: PU (Maybe Property)
xpProperty = xpOption $ xpAttr "property" xpPropertyValue
xpPropertyValue :: PU Property
xpPropertyValue = xpAlt tag ps
where
tag A = 1
tag B = 2
ps = [ xpTextAttr "a"
, xpTextAttr "b"
]
main :: IO ()
main = do
putStrLn $ showPickled [ withIndent yes ] someThings
return ()
此处,xpProperty
创建或读取一个 @property
属性,然后使用 xpPropertyValue
计算出该值。 xpPropertyValue
根据值的值构造函数确定值:A
给出 "a"
并且 B
给出 "b"
并且值是使用 xpTextAttr
功能。这里的问题是 xpTextAttr
是 String -> PU String
,我正试图在需要 PU Property
的地方使用它。但是我无法找到另一种生成 PU Property
值的方法,该方法依赖于 Property
值的值构造函数。
这没有正确使用 xpTextAttr
。首先,它的第一个参数应该是属性名称 "property"
,其次,它 return 是它匹配的文本。
您想 return 构造函数分别 A
或 B
。
您需要使用 xpWrap
指定 属性("a"
或 "b"
)的文本内容与那些构造函数之间的映射(双向)。我相信标签是基于 0 的,所以 0 和 1。
where
tag A = 0
tag B = 1
ps = [ xpWrap (const A,const "a") $ xpTextAttr "property"
, xpWrap (const B,const "b") $ xpTextAttr "property"
]
那么对xpAttr
的调用是错误的。老实说,我不确定 xpAttr
的用途,与限定名称有关。事实上 xpProperty
的足够代码是
xpProperty :: PU (Maybe Property)
xpProperty = xpOption $ xpPropertyValue