Yog.FSharp
Getting Started Examples API Reference GitHub

GraphML Serialization & Deserialization

This example demonstrates exporting and importing graphs using GraphML, the standard XML format supported by tools like Gephi, yEd, and Cytoscape.

Serialization

#I "../../src/Yog.FSharp/bin/Debug/net10.0"
#r "Yog.FSharp.dll"

open Yog.Model
open Yog.IO.GraphML

// Build a small directed graph
let graph =
    empty Directed
    |> addNode 1 "Alice" |> addNode 2 "Bob" |> addNode 3 "Carol"
    |> addEdge 1 2 "friend"
    |> addEdge 2 3 "colleague"
    |> addEdge 1 3 "neighbor"

// Serialize to GraphML XML
let xml = serialize graph
printfn "=== GraphML Output ==="
printfn "%s" xml

Round-Trip Deserialization

We can parse GraphML back into a Yog graph:

let loaded = deserialize xml

printfn "\n=== Round-Trip Verification ==="
printfn "Nodes: %d" (nodeCount loaded)
printfn "Edges:"
for src in allNodes loaded do
    for (dst, data) in successors src loaded do
        let weight = Map.tryFind "weight" data |> Option.defaultValue "?"
        printfn "  %d -> %d [%s]" src dst weight

Custom Types with serializeWith

For graphs with structured data, use serializeWith to control attribute mapping:

type Person = { Name: string; Role: string }

let team =
    empty Directed
    |> addNode 1 { Name = "Alice"; Role = "Lead" }
    |> addNode 2 { Name = "Bob"; Role = "Dev" }
    |> addEdge 1 2 5

let customXml =
    serializeWith
        (fun p -> ["name", p.Name; "role", p.Role])
        (fun w -> ["weight", string w])
        team

printfn "\n=== Custom Attributes ==="
printfn "%s" customXml

Output

=== GraphML Output ===
<graphml xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns="http://graphml.graphdrawing.org/xmlns">
  <key id="label" for="node" attr.name="label" attr.type="string" />
  <key id="weight" for="edge" attr.name="weight" attr.type="string" />
  <graph id="G" edgedefault="directed">
    <node id="1">
      <data key="label">Alice</data>
    </node>
    <node id="2">
      <data key="label">Bob</data>
    </node>
    <node id="3">
      <data key="label">Carol</data>
    </node>
    <edge source="1" target="2">
      <data key="weight">friend</data>
    </edge>
    <edge source="1" target="3">
      <data key="weight">neighbor</data>
    </edge>
    <edge source="2" target="3">
      <data key="weight">colleague</data>
    </edge>
  </graph>
</graphml>

=== Round-Trip Verification ===
Nodes: 3
Edges:
  1 -> 2 [friend]
  1 -> 3 [neighbor]
  2 -> 3 [colleague]

=== Custom Attributes ===
<graphml xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns="http://graphml.graphdrawing.org/xmlns">
  <key id="name" for="node" attr.name="name" attr.type="string" />
  <key id="role" for="node" attr.name="role" attr.type="string" />
  <key id="weight" for="edge" attr.name="weight" attr.type="string" />
  <graph id="G" edgedefault="directed">
    <node id="1">
      <data key="name">Alice</data>
      <data key="role">Lead</data>
    </node>
    <node id="2">
      <data key="name">Bob</data>
      <data key="role">Dev</data>
    </node>
    <edge source="1" target="2">
      <data key="weight">5</data>
    </edge>
  </graph>
</graphml>

When to Use GraphML

GraphML is ideal when you need to exchange graphs with external tools. Unlike JSON, it supports typed attributes and namespaces, and is the native format for tools like Gephi, yEd, Cytoscape, and NetworkX.

val graph: obj
val xml: string
val printfn: format: Printf.TextWriterFormat<'T> -> 'T
val loaded: obj
val src: int
val dst: int
val data: Map<string,string>
val weight: string
Multiple items
module Map from Microsoft.FSharp.Collections

--------------------
type Map<'Key,'Value (requires comparison)> = interface IReadOnlyDictionary<'Key,'Value> interface IReadOnlyCollection<KeyValuePair<'Key,'Value>> interface IEnumerable interface IStructuralEquatable interface IComparable interface IEnumerable<KeyValuePair<'Key,'Value>> interface ICollection<KeyValuePair<'Key,'Value>> interface IDictionary<'Key,'Value> new: elements: ('Key * 'Value) seq -> Map<'Key,'Value> member Add: key: 'Key * value: 'Value -> Map<'Key,'Value> ...

--------------------
new: elements: ('Key * 'Value) seq -> Map<'Key,'Value>
val tryFind: key: 'Key -> table: Map<'Key,'T> -> 'T option (requires comparison)
module Option from Microsoft.FSharp.Core
val defaultValue: value: 'T -> option: 'T option -> 'T
type Person = { Name: string Role: string }
Multiple items
val string: value: 'T -> string

--------------------
type string = System.String
val team: obj
val customXml: string
val id: x: 'T -> 'T