graphml

package
v0.11.0 Latest Latest
Warning

This package is not in the latest version of its module.

Go to latest
Published: Aug 13, 2026 License: MIT Imports: 15 Imported by: 0

Documentation

Overview

Package graphml reads and writes graphs in the GraphML XML dialect (http://graphml.graphdrawing.org/). v1 supports the commonly-encountered shape: <node id="...">, <edge source="..." target="..."> with an optional <data key="..."> carrying an int64 weight under a <key id="..." attr.name="weight" .../> declaration.

Index

Examples

Constants

View Source
const DefaultMaxBytes int64 = 128 << 20 // 128 MiB

DefaultMaxBytes is the default ceiling, in bytes, on the amount of input the default read entry points will consume before failing with ErrInputTooLarge. It guards against memory exhaustion from untrusted documents (a crafted multi-gigabyte GraphML file, for example). The capped variants (ReadIntoCappedCtx, ReadWithPropsCappedCtx) accept an explicit ceiling; a value of zero or less disables the cap.

Peak memory

The reader streams the document element by element: it folds each <node>/<edge> into the graph as that element is decoded rather than materialising the whole document as a struct-per-element DOM first. Peak transient memory therefore tracks the resulting graph — itself bounded by the input, and the input by this cap — plus a single element's working set, not a multiple of the input inflated by a retained DOM. (An earlier revision decoded the whole document with dec.Decode; a 128 MiB file of millions of tiny <edge/>/<node/>/<key/> tags then forced 2.2–3.4 GiB of transient heap. See ReadIntoCappedCtx.) encoding/xml still does not bound the size of a single token, so a pathological oversized token (an unterminated attribute value or chardata run) is buffered up to maxBytes with the decoder's usual ~3–4× working-set factor; that single-token transient — not a whole-document DOM — is now the worst case.

DefaultMaxBytes is set to 128 MiB. Callers importing larger trusted documents pass an explicit ceiling to the capped variants; callers parsing untrusted input should keep the default or lower it further.

Variables

View Source
var (
	ErrPropertyValueTooLarge  = errors.New("graphml: encoded property value exceeds size limit")
	ErrPropertyNestingTooDeep = errors.New("graphml: property value nesting too deep")
)

ErrPropertyValueTooLarge is the fail-stop guard against the nested-list re-escaping blowup (#1792); ErrPropertyNestingTooDeep guards recursion depth.

View Source
var ErrInputTooLarge = errors.New("graphml: input exceeds maximum size")

ErrInputTooLarge is returned by the read functions when the input stream exceeds the configured byte ceiling. The decoder stops drawing bytes from the input as soon as the limit is crossed; note, however, that a single oversized token may already have been buffered by encoding/xml up to the cap before the limit trips, so the decoder's peak working set is a multiple of the cap (see DefaultMaxBytes).

View Source
var ErrInvalidXMLChar = errors.New("graphml: value contains a character not representable in XML 1.0")

ErrInvalidXMLChar is returned by WriteWithProps and WriteWithPropsCtx when a node id, property key, or string property value contains a character that XML 1.0 cannot represent — the C0 control characters other than tab, newline, and carriage return (U+0000–U+0008, U+000B, U+000C, U+000E–U+001F), or an invalid UTF-8 byte.

Go's encoding/xml silently substitutes such characters with the Unicode replacement character (U+FFFD), which destroys the original bytes irreversibly. To preserve integrity the writer fails fast with this typed error rather than emitting corrupted output; callers needing to carry arbitrary bytes through a property should use the JSONL encoder, which escapes control characters losslessly, or store the payload as a lpg.BytesValue.

View Source
var ErrTooManyData = errors.New("graphml: too many <data> children on a single element")

ErrTooManyData is returned when a single <node> or <edge> carries more than [maxDataPerElement] <data> children.

View Source
var ErrTooManyKeys = errors.New("graphml: too many <key> declarations")

ErrTooManyKeys is returned when a document declares more than [maxKeyDecls] <key> elements — a schema flood used to amplify memory.

Functions

func ReadInto

func ReadInto(r io.Reader) (*adjlist.AdjList[string, int64], int, error)

ReadInto parses a GraphML document from r into an adjacency list. Returns the loaded list, the number of edges added, and an error on parse failure.

func ReadIntoCappedCtx added in v0.2.0

func ReadIntoCappedCtx(ctx context.Context, r io.Reader, maxBytes int64) (*adjlist.AdjList[string, int64], int, error)

ReadIntoCappedCtx is ReadIntoCtx with an explicit input-size ceiling. When maxBytes > 0 the decoder fails with ErrInputTooLarge the moment consumption exceeds the limit, before the whole document is buffered; a value of zero or less disables the cap.

On any error the returned graph is nil (see ReadIntoCtx); the import is all-or-nothing at the in-memory level.

func ReadIntoCtx

func ReadIntoCtx(ctx context.Context, r io.Reader) (*adjlist.AdjList[string, int64], int, error)

ReadIntoCtx is the context-aware variant of ReadInto. ctx.Err() is checked every 4096 edges. The input is capped at DefaultMaxBytes; use ReadIntoCappedCtx for an explicit ceiling.

On any error — a parse error, context cancellation, or the ErrInputTooLarge cap — the returned graph is nil; the import is all-or-nothing at the in-memory level, so a caller cannot accidentally commit a half-built graph. The typed error is returned unchanged; only the graph value is discarded.

func ReadWithProps

func ReadWithProps(r io.Reader) (*lpg.Graph[string, int64], int, error)

ReadWithProps parses a GraphML document from r and returns an lpg.Graph with typed node properties derived from <key> declarations and <data> elements. Edge weights are read via the standard "weight" key. The second return value is the number of edges added.

func ReadWithPropsCappedCtx added in v0.2.0

func ReadWithPropsCappedCtx(ctx context.Context, r io.Reader, maxBytes int64) (*lpg.Graph[string, int64], int, error)

ReadWithPropsCappedCtx is ReadWithPropsCtx with an explicit input-size ceiling. When maxBytes > 0 the decoder fails with ErrInputTooLarge the moment consumption exceeds the limit, before the whole document is buffered; a value of zero or less disables the cap.

On any error the returned graph is nil (see ReadWithPropsCtx); the import is all-or-nothing at the in-memory level.

func ReadWithPropsCtx

func ReadWithPropsCtx(ctx context.Context, r io.Reader) (*lpg.Graph[string, int64], int, error)

ReadWithPropsCtx is the context-aware variant of ReadWithProps. The input is capped at DefaultMaxBytes; use ReadWithPropsCappedCtx for an explicit ceiling.

On any error — a parse error, context cancellation, or the ErrInputTooLarge cap — the returned graph is nil; the import is all-or-nothing at the in-memory level, so a caller cannot accidentally commit a half-built graph. The typed error is returned unchanged; only the graph value is discarded.

func Write

func Write(w io.Writer, a *adjlist.AdjList[string, int64]) error

Write streams a GraphML document representing a to w. The output includes a single <graph> with directed or undirected edgedefault inferred from a, a <key for=edge attr.name=weight attr.type=long> declaration, and one <node>/<edge> per node and edge.

Example

ExampleWrite shows a GraphML round-trip: marshal a directed, weighted graph to XML with Write, then unmarshal it back with ReadInto and confirm the structure survived.

package main

import (
	"bytes"
	"fmt"

	"github.com/FlavioCFOliveira/GoGraph/graph/adjlist"
	"github.com/FlavioCFOliveira/GoGraph/graph/io/graphml"
)

func main() {
	src := adjlist.New[string, int64](adjlist.Config{Directed: true})
	_ = src.AddEdge("a", "b", 7)
	_ = src.AddEdge("b", "c", 9)

	var buf bytes.Buffer
	if err := graphml.Write(&buf, src); err != nil {
		panic(err)
	}

	dst, edges, err := graphml.ReadInto(&buf)
	if err != nil {
		panic(err)
	}

	fmt.Println("edges read:", edges)
	fmt.Println("order:", dst.Order())
	fmt.Println("size:", dst.Size())
	fmt.Println("a->b:", dst.HasEdge("a", "b"))
}
Output:
edges read: 2
order: 3
size: 2
a->b: true

func WriteCtx

func WriteCtx(ctx context.Context, w io.Writer, a *adjlist.AdjList[string, int64]) error

WriteCtx is the context-aware variant of Write. ctx.Err() is checked at the start of node and edge encoding; on cancellation returns the wrapped ctx.Err.

func WriteWithProps

func WriteWithProps(w io.Writer, g *lpg.Graph[string, int64]) error

WriteWithProps writes a GraphML document to w for the LPG g. A <key> declaration is emitted for every property key encountered across all nodes, with attr.type set to the GraphML equivalent of the first value seen for that key. Properties are serialised as <data> child elements of their respective <node> elements. Edge weights are written with the standard id="w" key.

Tombstoned nodes — those removed via lpg.Graph.RemoveNode — are excluded, together with every incident edge and every <key> declaration only their properties would justify, so an export→import round trip never resurrects deleted data.

Example

ExampleWriteWithProps shows the labelled-property-graph round-trip: WriteWithProps serialises node properties as <data> elements and ReadWithProps restores them, so a typed property recovers its value.

package main

import (
	"bytes"
	"fmt"

	"github.com/FlavioCFOliveira/GoGraph/graph/adjlist"
	"github.com/FlavioCFOliveira/GoGraph/graph/io/graphml"
	"github.com/FlavioCFOliveira/GoGraph/graph/lpg"
)

func main() {
	src := lpg.New[string, int64](adjlist.Config{Directed: true})
	_ = src.AddEdge("alice", "bob", 1)
	_ = src.SetNodeProperty("alice", "age", lpg.Int64Value(30))

	var buf bytes.Buffer
	if err := graphml.WriteWithProps(&buf, src); err != nil {
		panic(err)
	}

	dst, _, err := graphml.ReadWithProps(&buf)
	if err != nil {
		panic(err)
	}

	got, ok := dst.GetNodeProperty("alice", "age")
	age, _ := got.Int64()
	fmt.Println("alice has age:", ok)
	fmt.Println("alice.age:", age)
}
Output:
alice has age: true
alice.age: 30

func WriteWithPropsCtx

func WriteWithPropsCtx(ctx context.Context, w io.Writer, g *lpg.Graph[string, int64]) error

WriteWithPropsCtx is the context-aware variant of WriteWithProps. ctx.Err() is checked before the node and edge encoding phases.

Types

This section is empty.

Jump to

Keyboard shortcuts

? : This menu
/ : Search site
f or F : Jump to
y or Y : Canonical URL