xmlgen: создание узлов XML со смешанным содержимым (т.е. как с основным текстом, так и с вложенными элементами XML) в Haskell

Я пытаюсь сгенерировать XML со смешанными узлами контента (имеет как основной текст, так и дочерние узлы), как показано ниже:

<person>
some text
<hugo age="24">thingy</hugo>
</person>

Я использую библиотеку xmlgen.

Вот как далеко я добрался:

import Text.XML.Generator
import qualified Data.ByteString as B

makeElt = xelem "person" $
            xelems $ (xtext "some text" : 
                      (xelem "hugo" (xattr "age" "24" <#> 
                                     xtext "thingy")))

main = do
  let elt = makeElt
  B.putStr . xrender $ doc defaultDocInfo elt

Это не компилируется, и сообщение об ошибке GHC мне непонятно (как новичку):

$ runhaskell test.hs

test.hs:6:24:
    Couldn't match type `Elem' with `Xml Elem'
    The function `xelem' is applied to two arguments,
    but its type `[Char]
                  -> Text.XML.Generator.MkElemRes [Char] (Xml Attr, Xml Elem)'
    has only one
    In the second argument of `(:)', namely
      `(xelem "hugo" (xattr "age" "24" <#> xtext "thingy"))'
    In the second argument of `($)', namely
      `(xtext "some text"
        : (xelem "hugo" (xattr "age" "24" <#> xtext "thingy")))'

test.hs:6:24:
    Couldn't match type `Xml' with `[]'
    The function `xelem' is applied to two arguments,
    but its type `[Char]
                  -> Text.XML.Generator.MkElemRes [Char] (Xml Attr, Xml Elem)'
    has only one
    In the second argument of `(:)', namely
      `(xelem "hugo" (xattr "age" "24" <#> xtext "thingy"))'
    In the second argument of `($)', namely
      `(xtext "some text"
        : (xelem "hugo" (xattr "age" "24" <#> xtext "thingy")))'

Я достаточно близок к результату, который мне нужен, или я должен писать по-другому?

Я пытался найти примеры использования библиотеки xmlgen, но не нашел своего варианта использования. Любая помощь с благодарностью.

1 ответ

Решение

Проблема в выражении

(xtext "some text" : 
 (xelem "hugo" (xattr "age" "24" <#> 
                xtext "thingy")))

Часть после : (начиная с xelem "hugo") это не список. Хороший способ отладить проблемы такого типа - использовать ghci. Это то, что я сделал в первую очередь, и GHCI быстро ведет вас в правильном направлении:

*Text.XML.Generator> :t xtext "some text" : xelem "hugo" (xattr "age" "24" <#> xtext "thingy")

<interactive>:1:21:
    Couldn't match expected type `[Xml Elem]'
                with actual type `Xml Elem'
    In the return type of a call of `xelem'
    In the second argument of `(:)', namely
      `xelem "hugo" (xattr "age" "24" <#> xtext "thingy")'
    In the expression:
      xtext "some text"
      : xelem "hugo" (xattr "age" "24" <#> xtext "thingy")

Хороший вопрос, почему GHC в первую очередь выдает такое плохое сообщение об ошибке. Проблема в том, что тип результата xelem фактически перегружен xelem имеет тип n -> MkElemRes n c, Инстанциация для MkElemRes n c вы пытаетесь использовать в своем примере действительно тип функции, поэтому эта часть вашего примера верна. А вообще MkElemRes n c не обязательно должен быть типом функции, и поэтому GHC жалуется на два аргумента, где он ожидает только один (а именно тип MkElemRes n c).

Вот одно решение вашей первоначальной проблемы:

xelem "person" $ 
   xelems [xtext "some text", xelem "hugo" (xattr "age" "24" <#> xtext "thingy")]

Вот альтернативное решение:

xelem "person" $ xtext "some text" <> xelem "hugo" (xattr "age" "24" <#> xtext "thingy")
Другие вопросы по тегам