billstclair / elm-xml-extra / Xml.Extra

Simplify creating Decoders for XML input.

Most code will only need the two types, the decodeXml function, and the optionalTag & multipleTag decoders.

Example:

import XML.Extra exposing ( TagSpec, Required(..)
                          , decodeXml, optionalTag
                          )
import Json.Decode as JD exposing ( Decoder )

type alias PersonRecord =
    { name : String
    , age : Int
    , spouse : Maybe Person
    , children : List Person
    }

type Person =
    Person PersonRecord

personDecoder : Decoder Person
personDecoder =
    JD.map4 (\name age spouse children ->
                 Person <| PersonRecord name age spouse children
        (JD.field "name" JD.string)
        (JD.field "age" JD.int)
        (optionalTag "spouse"
             (JD.lazy (\_ -> personDecoder))
             personTagSpecs
        )
        (multipleTag "child"
             (JD.lazy (\_ -> personDecoder))
             personTagSpecs)

personTagSpecs : List TagSpec
personTagSpecs =
    [ ("name", Required)
    , ("age", Required)
    , ("spouse", Optional)
    , ("child", Multiple)
    ]

decodePersonXml : String -> Result String Person
decodePersonXml xml =
    decodeXml xml "person" personDecoder personTagSpecs

Xml =
    """
<person>
  <name>Irving</name>
  <age max="100">30</age>
  <sex>yes</sex>
  <favoriteColor>blue</favoriteColor>
  <spouse>
      <name>Joan</name>
      <age>28</age>
  </spouse>
  <child>
      <name>Bob</name>
      <age>1</age>
  </child>
  <child>
      <name>Sally</name>
      <age>3</age>
  </child>
</person>
    """

Types


type alias TagSpec =
( String, Required )

A description of one tag to decode: (, Required, )


type Required
    = Required
    | RequiredIgnore
    | Optional
    | Multiple

How to handle a tag in a TagSpec.

Required tags error if not there. RequiredIgnore tags must be in the XML, but are not returned. Optional tags will become null if not in the XML. Multiple tags become a list.

Decoders

requiredTag : String -> Json.Decode.Decoder value -> List TagSpec -> Json.Decode.Decoder value

A decoder for Required XML tags

If the TagSpec list is empty, then the Decoder is for a simple value. Otherwise, it's for a nested tag.

optionalTag : String -> Json.Decode.Decoder value -> List TagSpec -> Json.Decode.Decoder (Maybe value)

A decoder for Optional XML tags

If the TagSpec list is empty, then the Decoder is for a simple value. Otherwise, it's for a nested tag.

multipleTag : String -> Json.Decode.Decoder value -> List TagSpec -> Json.Decode.Decoder (List value)

A decoder for Multiple XML tags

If the TagSpec list is empty, then the Decoder is for a simple value. Otherwise, it's for a nested tag.

Functions

decodeXml : String -> String -> Json.Decode.Decoder value -> List TagSpec -> Result Error value

Decode an XML string containing a single tag into an Elm value.

Errors


type Error
    = XmlError String
    | DecodeError DecodeDetails

The error return from decodeXml


type alias DecodeDetails =
{ value : Json.Decode.Value
, msg : String 
}

Details about a decode error.

value is the input to the decoder. msg is the error from Json.Decode.decodeValue with the current value appended.

Low-level decoder and functions

tagDecoder : Json.Decode.Decoder value -> List TagSpec -> Json.Decode.Decoder value

Decode the contents of an XML tag with subtags.

Each TagSpec pulls one or more matching tags from the list.

Unspecified tags in the parsed Value are skipped.

You end up with a single JSON object, with the tags as keys, to which you can apply a standard JSON decoder.

stringToJson : String -> Result String Json.Encode.Value

Decode an XML string into a simplified Json.Encode.Value.

xmlToJson2 : Xml.Value -> Json.Encode.Value

Convert the Xml.Value returned by Xml.Decode.decode to a Json.Encode.Value, removing all the attributes.