Home

Awesome

Fable.SimpleXml Build Status Build Status Nuget

A simple library for parsing Xml strings into structured Xml data. Works in browser and node without installing any extra javascript dependencies. It is written using parser combinators from Fable.Parsimmon

See the library in action in the Test page

Installation

Install from nuget using paket

paket add nuget Fable.SimpleXml --project path/to/YourProject.fsproj

Make sure the references are added to your paket files

# paket.dependencies (solution-wide dependencies)
nuget Fable.SimpleXml

# paket.refernces (project-specific dependencies)
Fable.SimpleXml

Example usage

type Person = { Id : int; Name: string }

let createPerson id name =
    { Id = id; Name = name }

"""
<People>
    <Person Id=1 Name='John' />
    <Person Id='2' Name="Jane" />
</People>
"""
|> SimpleXml.parseElement
|> SimpleXml.findElementsByName "Person"
|> List.map (fun elem ->
    let id = int (Map.find "Id" elem.Attributes)
    let name = Map.find "Name" elem.Attributes
    createPerson id name)

Or you can inspect the content of the elements:

testCase "SimpleXml use case" <| fun test ->
    "<People>
        <Person>John</Person>
        <Person>Jane</Person>
    </People>"
    |> SimpleXml.parseElementNonStrict
    |> SimpleXml.children
    |> List.map SimpleXml.content
    |> test.areEqual [ "John"; "Jane" ]

API

// Parsing functions
SimpleXml.tryParseElement : string -> Option<XmlElement>
SimpleXml.parseElement : string -> XmlElement
SimpleXml.tryParseDocument : string -> Option<XmlDocument>
SimpleXml.parseDocument : string -> XmlDocument

// Non strict parsing functions, exludes text nodes between elements (leaving Content intact)
SimpleXml.parseElementNonStrict : string -> XmlElement
SimpleXml.tryParseElementNonStrict : string -> Option<XmlElement>
SimpleXml.tryParseDocumentNonStrict : string -> Option<XmlDocument>
SimpleXml.parseDocumentNonStrict : string -> XmlDocument

// Search functions
SimpleXml.findElementsBy : (XmlElement -> bool) -> XmlElement -> XmlElement list
SimpleXml.findElementsByName : string -> XmlElement -> XmlElement list
SimpleXml.findElementByName : string -> XmlElement -> XmlElement
SimpleXml.findElementsByExactAttributes : Map<string, string> -> XmlElement -> XmlElement list
SimpleXml.findElementByAttribute : string -> string -> XmlElement -> XmlElement list
SimpleXml.tryFindElementByAttributes : Map<string, string> -> XmlElement -> Option<XmlElement>
SimpleXml.tryFindElementByName : string -> XmlElement -> Option<XmlElement>
/// ... AND MORE ...

Where XmlElement and XmlDocument are defined as follows:

type XmlElement = {
    Namespace : string option
    Name : string
    Attributes : Map<string, string>
    Content : string
    Children : XmlElement list
    SelfClosing : bool
    IsTextNode : bool
    IsComment : bool
}

type XmlDocument = {
    Declaration : Map<string, string> option
    Root : XmlElement
}

Generate Xml:

Create Xml from a tree structure. Opening the Fable.SimpleXml.Generator module, gives you access to these:

Indentation is not supported yet. PR's are welcome ;)

open Fable.SimpleXml.Generator

let people =
    node "people" [ ] [
        leaf "person" [
            attr.value("name", "John Doe")
            attr.value("age", 26)
            attr.value("married", false)
        ]

        leaf "person" [
            attr.value("name", "Jane Doe")
            attr.value("age", 25)
            attr.value("married", true)
        ]
    ]

serializeXml people

will generate:

<people>
  <person name="John Doe" age="26" married="false" />
  <person name="Jane Doe" age="25" married="true" />
</people>

Use nested property

let person =
    node "person" [ ] [
        node "id" [ ] [ text "1" ]
        node "name" [ ] [ text "John" ]
        node "married" [ ] [ text "false" ]
    ]

serializeXml person

will generate

<person>
    <id>1</id>
    <name>John</name>
    <married>false</married>
</person>

Access any xml to update/change it

let xml =
    """people>
        <person name="John Doe" age="26" married="false" />
        <person name="Jane Doe" age="25" married="true" />
    </people>"""

let parsedXml = SimpleXml.parseElement xml

// .. Work with the xml by removing, changing, adding any xml element or attribute including comments and namespaces. ..

// Revert XmlElement back to xml string

let xmlTree = Generator.ofXmlElement parsedXml

serializeXml xmlTree

Running sample app locally

./build.sh RunSample
#or
build RunSample

Running the tests live

./build.sh RunLiveTests

Building the tests and running QUnit cli runner

./build.sh RunTests

or just Ctrl + Shift + B to run the cli tests as a VS Code task