我刚开始使用HXT解析一些XML文档,并且想知道如何处理元素排序。
考虑以下两个具有等效数据的XML片段。
<!-- Version 1 -->
<logistics>
<deliveryDate>2015-02-24T14:35:00Z</deliveryDate>
<deliveryAddress>Street Name 12, 93483 City, Country</deliveryAddress>
</logistics>
<!-- Version 2 -->
<logistics>
<deliveryAddress>Street Name 12, 93483 City, Country</deliveryAddress>
<deliveryDate>2015-02-24T14:35:00Z</deliveryDate>
</logistics>
为了支持deliveryDate
和deliverAddress
的排序,我必须将XHT的xpPair
函数替换为我自己的xpUnorderedPair
函数:
xpUnorderedPair :: PU a -> PU b -> PU (a,b)
xpUnorderedPair pa pb = xpAlt (const 0) ps
where ps = [ xpPair pa pb
, xpWrap (swap,undefined) $ xpPair pb pa ],
允许我编写以下pickler函数:
xpLogisticsRequirements :: PU LogisticsRequirements
xpLogisticsRequirements = xpElem "logistics" $
xpWrap (uncurry LogisticsRequirements,\r -> (deliveryDate r,deliveryAddr r)) $
xpUnorderedPair (xpElem "deliveryDate" xpickle)
(xpElem "deliveryAddress" xpText)
其中LogisticsRequirements
的类型为UTCTime -> String -> LogisticsRequirement
。
现在我可以使用xpTriple
执行相同操作,创建我的xpUnorderedTriple
:
xpUnorderedTriple :: PU a -> PU b -> PU c -> PU (a,b,c)
xpUnorderedTriple a' b' c' = xpAlt (const 0) ps
where ps = [ xpWrap (\(a,b,c) -> (a,b,c),undefined) $ xpTriple a' b' c'
, xpWrap (\(a,c,b) -> (a,b,c),undefined) $ xpTriple a' c' b'
, xpWrap (\(b,c,a) -> (a,b,c),undefined) $ xpTriple b' c' a'
, xpWrap (\(b,a,c) -> (a,b,c),undefined) $ xpTriple b' a' c'
, xpWrap (\(c,a,b) -> (a,b,c),undefined) $ xpTriple c' a' b'
, xpWrap (\(c,b,a) -> (a,b,c),undefined) $ xpTriple c' b' a' ]
我可以继续创建这些越来越大的函数(xpUnordered5将有120个排列),但这似乎不对。对于固定数字(即pair,triple,t4,t5等),我想我可以使用Template Haskell来创建函数,但是当我想解析不同元素的 list 时会发生什么。 / p>
考虑XML输入,例如:
<myList>
<name>MyList1</name>
<elemA>...</elemA>
<elemA>...</elemA>
<elemB>...</elemB>
<elemA>...</elemA>
<elemB>...</elemB>
<elemC>...</elemC>
<elemB>...</elemB>
</myList>,
我将如何将它们变成
data MyList = MyList { name :: String
, elemsA :: [ElemA]
, elemsB :: [ElemB]
, elemsC :: [ElemC] },
考虑到我有必要的泡菜功能,
instance XmlPicker ElemA where
xpickle = xpElemA
instance XmlPicker ElemB where
xpickle = xpElemB
instance XmlPicker ElemC where
xpickle = xpElemC
我猜一个选项可能是对元素列表进行排序,然后应用顺序选择器
xpYogurt :: PU MyList
xpYogurt = xpElem "myList" $
xpWrap (uncurry4 MyList,\l -> (name l
,elemsA l
,elemsB l
,elemsC l)) $
xp4Tuple (xpElem "name" xpPrim)
(xpList xpElemA)
(xpList xpElemB)
(xpList xpElemC)
但这似乎不太优雅,需要额外的排序逻辑!
根据viorior的建议,可以定义数据类型:
data Elem = ElemA ElemA
| ElemB ElemB
| ElemC ElemC
然后将unpickled元素转换为它们各自的类型,但是这种方法的问题是,然后可以解析上面的列表,它不允许取消下面稍微修改的XML(注意{{1的新位置)元素):
<name>
答案 0 :(得分:1)
到目前为止,还没有提供对实际问题的合适答案,所以这里是一种替代(并且显而易见)的XML表示方法,无论如何看起来更优雅:
<myList>
<name>MyList1</name>
<elements>
<elemA>...</elemA>
<elemA>...</elemA>
<elemB>...</elemB>
<elemA>...</elemA>
<elemB>...</elemB>
<elemC>...</elemC>
<elemB>...</elemB>
</elements>
</myList>.