1// Copyright ©2018 The Gonum Authors. All rights reserved. 2// Use of this source code is governed by a BSD-style 3// license that can be found in the LICENSE file. 4 5// Package gexf12 implements marshaling and unmarshaling of GEXF1.2 documents. 6// 7// For details of GEXF see https://gephi.org/gexf/format/. 8package gexf12 // import "gonum.org/v1/gonum/graph/formats/gexf12" 9 10import ( 11 "bytes" 12 "encoding/xml" 13 "time" 14) 15 16// BUG(kortschak): The namespace for GEFX1.2 is 1.2draft, though it has 17// already been deprecated. There is no specification for 1.3, although 18// it is being used in the wild. 19 20// Content holds a GEFX graph and metadata. 21type Content struct { 22 XMLName xml.Name `xml:"http://www.gexf.net/1.2draft gexf"` 23 Meta *Meta `xml:"meta,omitempty"` 24 Graph Graph `xml:"graph"` 25 // Version must be "1.2". 26 Version string `xml:"version,attr"` 27 Variant string `xml:"variant,attr,omitempty"` 28} 29 30// Meta holds optional metadata associated with the graph. 31type Meta struct { 32 Creator string `xml:"creator,omitempty"` 33 Keywords string `xml:"keywords,omitempty"` 34 Description string `xml:"description,omitempty"` 35 LastModified time.Time `xml:"lastmodifieddate,attr,omitempty"` 36} 37 38// MarshalXML implements the xml.Marshaler interface. 39func (t *Meta) MarshalXML(e *xml.Encoder, start xml.StartElement) error { 40 type T Meta 41 var layout struct { 42 *T 43 LastModified *xsdDate `xml:"lastmodifieddate,attr,omitempty"` 44 } 45 layout.T = (*T)(t) 46 layout.LastModified = (*xsdDate)(&layout.T.LastModified) 47 return e.EncodeElement(layout, start) 48} 49 50// UnmarshalXML implements the xml.Unmarshaler interface. 51func (t *Meta) UnmarshalXML(d *xml.Decoder, start xml.StartElement) error { 52 type T Meta 53 var overlay struct { 54 *T 55 LastModified *xsdDate `xml:"lastmodifieddate,attr,omitempty"` 56 } 57 overlay.T = (*T)(t) 58 overlay.LastModified = (*xsdDate)(&overlay.T.LastModified) 59 return d.DecodeElement(&overlay, &start) 60} 61 62// Graph stores the graph nodes, edges, dynamics and visualization data. 63type Graph struct { 64 Attributes []Attributes `xml:"attributes"` 65 Nodes Nodes `xml:"nodes"` 66 Edges Edges `xml:"edges"` 67 // TimeFormat may be one of "integer", "double", "date" or "dateTime". 68 TimeFormat string `xml:"timeformat,attr,omitempty"` 69 Start string `xml:"start,attr,omitempty"` 70 StartOpen string `xml:"startopen,attr,omitempty"` 71 End string `xml:"end,attr,omitempty"` 72 EndOpen string `xml:"endopen,attr,omitempty"` 73 // DefaultEdgeType may be one of "directed", "undirected" or "mutual". 74 DefaultEdgeType string `xml:"defaultedgetype,attr,omitempty"` 75 // IDType may be one of "integer" or "string". 76 IDType string `xml:"idtype,attr,omitempty"` 77 // Mode may be "static" or "dynamic". 78 Mode string `xml:"mode,attr,omitempty"` 79} 80 81// Attributes holds a collection of potentially dynamic attributes 82// associated with a graph. 83type Attributes struct { 84 Attributes []Attribute `xml:"attribute,omitempty"` 85 // Class be one of "node" or "edge". 86 Class string `xml:"class,attr"` 87 // Mode may be "static" or "dynamic". 88 Mode string `xml:"mode,attr,omitempty"` 89 Start string `xml:"start,attr,omitempty"` 90 StartOpen string `xml:"startopen,attr,omitempty"` 91 End string `xml:"end,attr,omitempty"` 92 EndOpen string `xml:"endopen,attr,omitempty"` 93} 94 95// Attribute holds a single graph attribute. 96type Attribute struct { 97 ID string `xml:"id,attr"` 98 Title string `xml:"title,attr"` 99 // Type may be one of "integer", "long", "double", "float", 100 // "boolean", "liststring", "string", or "anyURI". 101 Type string `xml:"type,attr"` 102 Default string `xml:"default,omitempty"` 103 Options string `xml:"options,omitempty"` 104} 105 106// Nodes holds a collection of nodes constituting a graph or subgraph. 107type Nodes struct { 108 Count int `xml:"count,attr,omitempty"` 109 Nodes []Node `xml:"node,omitempty"` 110} 111 112// Node is a single node and its associated attributes. 113type Node struct { 114 ID string `xml:"id,attr,omitempty"` 115 Label string `xml:"label,attr,omitempty"` 116 AttValues *AttValues `xml:"attvalues"` 117 Spells *Spells `xml:"spells"` 118 Nodes *Nodes `xml:"nodes"` 119 Edges *Edges `xml:"edges"` 120 ParentID string `xml:"pid,attr,omitempty"` 121 Parents *Parents `xml:"parents"` 122 Color *Color `xml:"http://www.gexf.net/1.2draft/viz color"` 123 Position *Position `xml:"http://www.gexf.net/1.2draft/viz position"` 124 Size *Size `xml:"http://www.gexf.net/1.2draft/viz size"` 125 Shape *NodeShape `xml:"http://www.gexf.net/1.2draft/viz shape"` 126 Start string `xml:"start,attr,omitempty"` 127 StartOpen string `xml:"startopen,attr,omitempty"` 128 End string `xml:"end,attr,omitempty"` 129 EndOpen string `xml:"endopen,attr,omitempty"` 130} 131 132// NodeShape holds the visual representation of a node with associated 133// dynamics. 134type NodeShape struct { 135 Spells *Spells `xml:"spells,omitempty"` 136 // Value be one of "disc", "square", "triangle", 137 // "diamond" or "image". 138 Shape string `xml:"value,attr"` 139 URI string `xml:"uri,attr,omitempty"` 140 Start string `xml:"start,attr,omitempty"` 141 StartOpen string `xml:"startopen,attr,omitempty"` 142 End string `xml:"end,attr,omitempty"` 143 EndOpen string `xml:"endopen,attr,omitempty"` 144} 145 146// Color represents a node or edge color and its associated dynamics. 147type Color struct { 148 Spells *Spells `xml:"spells,omitempty"` 149 R byte `xml:"r,attr"` 150 G byte `xml:"g,attr"` 151 B byte `xml:"b,attr"` 152 A float64 `xml:"a,attr,omitempty"` 153 Start string `xml:"start,attr,omitempty"` 154 StartOpen string `xml:"startopen,attr,omitempty"` 155 End string `xml:"end,attr,omitempty"` 156 EndOpen string `xml:"endopen,attr,omitempty"` 157} 158 159// Edges holds a collection of edges constituting a graph or subgraph. 160type Edges struct { 161 Count int `xml:"count,attr,omitempty"` 162 Edges []Edge `xml:"edge,omitempty"` 163} 164 165// Edge is a single edge and its associated attributes. 166type Edge struct { 167 ID string `xml:"id,attr,omitempty"` 168 AttValues *AttValues `xml:"attvalues"` 169 Spells *Spells `xml:"spells"` 170 Color *Color `xml:"http://www.gexf.net/1.2draft/viz color"` 171 Thickness *Thickness `xml:"http://www.gexf.net/1.2draft/viz thickness"` 172 Shape *Edgeshape `xml:"http://www.gexf.net/1.2draft/viz shape"` 173 Start string `xml:"start,attr,omitempty"` 174 StartOpen string `xml:"startopen,attr,omitempty"` 175 End string `xml:"end,attr,omitempty"` 176 EndOpen string `xml:"endopen,attr,omitempty"` 177 // Type may be one of directed, undirected, mutual 178 Type string `xml:"type,attr,omitempty"` 179 Label string `xml:"label,attr,omitempty"` 180 Source string `xml:"source,attr"` 181 Target string `xml:"target,attr"` 182 Weight float64 `xml:"weight,attr,omitempty"` 183} 184 185// AttVlues holds a collection of attribute values. 186type AttValues struct { 187 AttValues []AttValue `xml:"attvalue,omitempty"` 188} 189 190// AttValues holds a single attribute value and its associated dynamics. 191type AttValue struct { 192 For string `xml:"for,attr"` 193 Value string `xml:"value,attr"` 194 Start string `xml:"start,attr,omitempty"` 195 StartOpen string `xml:"startopen,attr,omitempty"` 196 End string `xml:"end,attr,omitempty"` 197 EndOpen string `xml:"endopen,attr,omitempty"` 198} 199 200// EdgeShape holds the visual representation of an edge with associated 201// dynamics. 202type Edgeshape struct { 203 // Shape be one of solid, dotted, dashed, double 204 Shape string `xml:"value,attr"` 205 Spells *Spells `xml:"spells,omitempty"` 206 Start string `xml:"start,attr,omitempty"` 207 StartOpen string `xml:"startopen,attr,omitempty"` 208 End string `xml:"end,attr,omitempty"` 209 EndOpen string `xml:"endopen,attr,omitempty"` 210} 211 212// Parents holds parent relationships between nodes in a hierarchical 213// graph. 214type Parents struct { 215 Parents []Parent `xml:"parent,omitempty"` 216} 217 218// Parent is a single parent relationship. 219type Parent struct { 220 For string `xml:"for,attr"` 221} 222 223// Position hold the spatial position of a node and its dynamics. 224type Position struct { 225 X float64 `xml:"x,attr"` 226 Y float64 `xml:"y,attr"` 227 Z float64 `xml:"z,attr"` 228 Spells *Spells `xml:"spells,omitempty"` 229 Start string `xml:"start,attr,omitempty"` 230 StartOpen string `xml:"startopen,attr,omitempty"` 231 End string `xml:"end,attr,omitempty"` 232 EndOpen string `xml:"endopen,attr,omitempty"` 233} 234 235// Size hold the visual size of a node and its dynamics. 236type Size struct { 237 Value float64 `xml:"value,attr"` 238 Spells *Spells `xml:"http://www.gexf.net/1.2draft/viz spells,omitempty"` 239 Start string `xml:"start,attr,omitempty"` 240 StartOpen string `xml:"startopen,attr,omitempty"` 241 End string `xml:"end,attr,omitempty"` 242 EndOpen string `xml:"endopen,attr,omitempty"` 243} 244 245// Thickness hold the visual thickness of an edge and its dynamics. 246type Thickness struct { 247 Value float64 `xml:"value,attr"` 248 Spells *Spells `xml:"http://www.gexf.net/1.2draft/viz spells,omitempty"` 249 Start string `xml:"start,attr,omitempty"` 250 StartOpen string `xml:"startopen,attr,omitempty"` 251 End string `xml:"end,attr,omitempty"` 252 EndOpen string `xml:"endopen,attr,omitempty"` 253} 254 255// Spells holds a collection of time dynamics for a graph entity. 256type Spells struct { 257 Spells []Spell `xml:"spell"` 258} 259 260// Spell is a time interval. 261type Spell struct { 262 Start string `xml:"start,attr,omitempty"` 263 StartOpen string `xml:"startopen,attr,omitempty"` 264 End string `xml:"end,attr,omitempty"` 265 EndOpen string `xml:"endopen,attr,omitempty"` 266} 267 268type xsdDate time.Time 269 270func (t *xsdDate) UnmarshalText(text []byte) error { 271 return _unmarshalTime(text, (*time.Time)(t), "2006-01-02") 272} 273 274func (t xsdDate) MarshalText() ([]byte, error) { 275 return []byte((time.Time)(t).Format("2006-01-02")), nil 276} 277 278func (t xsdDate) MarshalXML(e *xml.Encoder, start xml.StartElement) error { 279 if (time.Time)(t).IsZero() { 280 return nil 281 } 282 m, err := t.MarshalText() 283 if err != nil { 284 return err 285 } 286 return e.EncodeElement(m, start) 287} 288 289func (t xsdDate) MarshalXMLAttr(name xml.Name) (xml.Attr, error) { 290 if (time.Time)(t).IsZero() { 291 return xml.Attr{}, nil 292 } 293 m, err := t.MarshalText() 294 return xml.Attr{Name: name, Value: string(m)}, err 295} 296 297func _unmarshalTime(text []byte, t *time.Time, format string) (err error) { 298 s := string(bytes.TrimSpace(text)) 299 *t, err = time.Parse(format, s) 300 if _, ok := err.(*time.ParseError); ok { 301 *t, err = time.Parse(format+"Z07:00", s) 302 } 303 return err 304} 305