0

我刚刚开始使用 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>

为了同时支持deliveryDatedeliverAddress我不得不xpPair用我自己的函数替换 XHT 的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 个排列),但这似乎不对。对于固定数字(即对、三重、t4、t5 等),我想我可以使用 Template Haskell 来创建函数,但是当我想解析不同元素的列表时会发生什么。

无序列表

考虑这样的 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

我猜一个选项可能是对元素列表进行排序,然后应用顺序pickler,

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 的元素转换为它们各自的类型,但这种方法的问题是,虽然可以解析上面的列表,但它不允许 unpickling 以下稍微修改的 XML(注意<name>元素的新位置):

<myList>
    <elemA>...</elemA>
    <elemA>...</elemA>
    <name>MyList1</name>
    <elemB>...</elemB>
    <elemA>...</elemA>
    <elemB>...</elemB>
    <elemC>...</elemC>
    <elemB>...</elemB>
</myList>,
4

1 回答 1

1

到目前为止,还没有为实际问题提供合适的答案,所以这里有一个替代的(也是显而易见的)XML 表示方法,无论如何看起来更优雅:

<myList>
    <name>MyList1</name>
    <elements>
        <elemA>...</elemA>
        <elemA>...</elemA>
        <elemB>...</elemB>
        <elemA>...</elemA>
        <elemB>...</elemB>
        <elemC>...</elemC>
        <elemB>...</elemB>
    </elements>
</myList>.
于 2014-08-28T07:18:50.677 回答