26 using System.Collections.Generic;
28 using System.Globalization;
31 using System.Xml.Linq;
33 namespace Satsuma.IO.GraphML
56 public string Name {
get;
set; }
62 public string Id {
get;
set; }
77 default:
return "all";
95 protected virtual void LoadFromKeyElement(XElement xKey)
97 var attrName = xKey.Attribute(
"attr.name");
98 Name = (attrName == null ? null : attrName.Value);
99 Domain = ParseDomain(xKey.Attribute(
"for").Value);
100 Id = xKey.Attribute(
"id").Value;
102 var _default = Utils.ElementLocal(xKey,
"default");
103 ReadData(_default, null);
108 public virtual XElement GetKeyElement()
111 xKey.SetAttributeValue(
"attr.name", Name);
112 xKey.SetAttributeValue(
"for", DomainToGraphML(Domain));
113 xKey.SetAttributeValue(
"id", Id);
115 XElement xDefault = WriteData(null);
116 if (xDefault != null)
131 public abstract void ReadData(XElement x,
object key);
136 public abstract XElement WriteData(
object key);
143 public bool HasDefaultValue {
get;
set; }
145 public T DefaultValue {
get;
set; }
149 public Dictionary<object, T> Values {
get;
private set; }
151 protected DictionaryProperty() : base()
153 HasDefaultValue =
false;
154 Values =
new Dictionary<object, T>();
160 HasDefaultValue =
false;
169 public bool TryGetValue(
object key, out T result)
171 if (Values.TryGetValue(key, out result))
return true;
174 result = DefaultValue;
181 public override void ReadData(XElement x,
object key)
186 if (key == null) HasDefaultValue =
false;
else Values.Remove(key);
191 T value = ReadValue(x);
194 HasDefaultValue =
true;
195 DefaultValue = value;
197 else Values[key] = value;
201 public override XElement WriteData(
object key)
205 return HasDefaultValue ? WriteValue(DefaultValue) : null;
210 if (!Values.TryGetValue(key, out value))
return null;
211 return WriteValue(value);
219 protected abstract T ReadValue(XElement x);
222 protected abstract XElement WriteValue(T value);
252 public sealed
class StandardProperty<T> : DictionaryProperty<T>
255 private static readonly
StandardType Type = ParseType(typeof(T));
257 private static readonly
string TypeString = TypeToGraphML(Type);
259 public StandardProperty()
265 internal StandardProperty(XElement xKey)
268 var attrType = xKey.Attribute(
"attr.type");
269 if (attrType == null || attrType.Value != TypeString)
270 throw new ArgumentException(
"Key not compatible with property.");
271 LoadFromKeyElement(xKey);
283 throw new ArgumentException(
"Invalid type for a standard GraphML property.");
296 default:
return "string";
300 private static object ParseValue(
string value)
305 case StandardType.Double:
return double.Parse(value, CultureInfo.InvariantCulture);
306 case StandardType.Float:
return float.Parse(value, CultureInfo.InvariantCulture);
307 case StandardType.Int:
return int.Parse(value, CultureInfo.InvariantCulture);
308 case StandardType.Long:
return long.Parse(value, CultureInfo.InvariantCulture);
309 default:
return value;
313 public override XElement GetKeyElement()
315 XElement x = base.GetKeyElement();
316 x.SetAttributeValue(
"attr.type", TypeString);
320 protected override T ReadValue(XElement x)
322 return (T)ParseValue(x.Value);
325 protected override XElement WriteValue(T value)
327 return new XElement(
"dummy", value.ToString());
344 public double X {
get;
set; }
346 public double Y {
get;
set; }
348 public double Width {
get;
set; }
350 public double Height {
get;
set; }
361 private readonly
string[] nodeShapeToString = {
"rectangle",
"roundrectangle",
"ellipse",
"parallelogram",
362 "hexagon",
"triangle",
"rectangle3d",
"octagon",
363 "diamond",
"trapezoid",
"trapezoid2"};
368 return (
NodeShape)(Math.Max(0, Array.IndexOf(nodeShapeToString, s)));
372 private string ShapeToGraphML(
NodeShape shape)
374 return nodeShapeToString[(int)shape];
380 XElement xGeometry = Utils.ElementLocal(xData,
"Geometry");
381 if (xGeometry != null)
383 X =
double.Parse(xGeometry.Attribute(
"x").Value, CultureInfo.InvariantCulture);
384 Y =
double.Parse(xGeometry.Attribute(
"y").Value, CultureInfo.InvariantCulture);
385 Width =
double.Parse(xGeometry.Attribute(
"width").Value, CultureInfo.InvariantCulture);
386 Height =
double.Parse(xGeometry.Attribute(
"height").Value, CultureInfo.InvariantCulture);
388 XElement xShape = Utils.ElementLocal(xData,
"Shape");
390 Shape = ParseShape(xShape.Attribute(
"type").Value);
394 public XElement ToXml()
396 return new XElement(
"dummy",
399 new XAttribute(
"x", X.ToString(CultureInfo.InvariantCulture)),
400 new XAttribute(
"y", Y.ToString(CultureInfo.InvariantCulture)),
401 new XAttribute(
"width", Width.ToString(CultureInfo.InvariantCulture)),
402 new XAttribute(
"height", Height.ToString(CultureInfo.InvariantCulture))),
404 new XAttribute(
"type", ShapeToGraphML(Shape)))
409 public override string ToString()
411 return ToXml().ToString();
445 var attrYFilesType = xKey.Attribute(
"yfiles.type");
446 if (attrYFilesType == null || attrYFilesType.Value !=
"nodegraphics")
447 throw new ArgumentException(
"Key not compatible with property.");
448 LoadFromKeyElement(xKey);
451 public override XElement GetKeyElement()
453 XElement x = base.GetKeyElement();
454 x.SetAttributeValue(
"yfiles.type",
"nodegraphics");
465 return value.
ToXml();
516 internal static readonly XNamespace xmlns =
"http://graphml.graphdrawing.org/xmlns";
517 private static readonly XNamespace xmlnsXsi =
"http://www.w3.org/2001/XMLSchema-instance";
518 internal static readonly XNamespace xmlnsY =
"http://www.yworks.com/xml/graphml";
519 private static readonly XNamespace xmlnsYed =
"http://www.yworks.com/xml/yed/3";
520 private const string xsiSchemaLocation =
"http://graphml.graphdrawing.org/xmlns\n" +
521 "http://graphml.graphdrawing.org/xmlns/1.0/graphml.xsd";
529 public IList<GraphMLProperty> Properties {
get;
private set; }
531 private readonly List<Func<XElement, GraphMLProperty>> PropertyLoaders;
535 Properties =
new List<GraphMLProperty>();
536 PropertyLoaders =
new List<Func<XElement, GraphMLProperty>>
538 x =>
new StandardProperty<bool>(x),
539 x =>
new StandardProperty<double>(x),
540 x =>
new StandardProperty<float>(x),
541 x =>
new StandardProperty<int>(x),
542 x =>
new StandardProperty<long>(x),
543 x =>
new StandardProperty<string>(x),
557 public void RegisterPropertyLoader(Func<XElement, GraphMLProperty> loader)
559 PropertyLoaders.Add(loader);
562 private static void ReadProperties(Dictionary<string, GraphMLProperty> propertyById, XElement x,
object obj)
564 foreach (var xData
in Utils.ElementsLocal(x,
"data"))
567 if (propertyById.TryGetValue(xData.Attribute(
"key").Value, out p))
573 public void Load(XDocument doc)
578 buildableGraph.
Clear();
579 XElement xGraphML = doc.Root;
583 Dictionary<string, GraphMLProperty> propertyById =
new Dictionary<string, GraphMLProperty>();
584 foreach (var xKey
in Utils.ElementsLocal(xGraphML,
"key"))
586 foreach (var handler
in PropertyLoaders)
592 propertyById[p.
Id] = p;
595 catch (ArgumentException) { }
600 XElement xGraph = Utils.ElementLocal(xGraphML,
"graph");
601 Directedness defaultDirectedness = (xGraph.Attribute(
"edgedefault").Value ==
"directed" ?
603 ReadProperties(propertyById, xGraph,
Graph);
605 Dictionary<string, Node> nodeById =
new Dictionary<string, Node>();
606 foreach (var xNode
in Utils.ElementsLocal(xGraph,
"node"))
608 Node node = buildableGraph.AddNode();
609 nodeById[xNode.Attribute(
"id").Value] = node;
610 ReadProperties(propertyById, xNode, node);
613 foreach (var xArc
in Utils.ElementsLocal(xGraph,
"edge"))
615 Node u = nodeById[xArc.Attribute(
"source").Value];
616 Node v = nodeById[xArc.Attribute(
"target").Value];
619 XAttribute dirAttr = xArc.Attribute(
"directed");
622 Arc arc = buildableGraph.AddArc(u, v, dir);
623 ReadProperties(propertyById, xArc, arc);
628 public void Load(XmlReader xml)
630 XDocument doc = XDocument.Load(xml);
636 public void Load(TextReader reader)
638 using (XmlReader xml = XmlReader.Create(reader))
643 public void Load(
string filename)
645 using (StreamReader reader =
new StreamReader(filename))
649 private void DefinePropertyValues(XmlWriter xml,
object obj)
651 foreach (var p
in Properties)
653 XElement x = p.WriteData(obj);
654 if (x == null)
continue;
656 x.SetAttributeValue(
"key", p.Id);
662 private void Save(XmlWriter xml)
664 xml.WriteStartDocument();
665 xml.WriteStartElement(
"graphml", xmlns.NamespaceName);
666 xml.WriteAttributeString(
"xmlns",
"xsi", null, xmlnsXsi.NamespaceName);
667 xml.WriteAttributeString(
"xmlns",
"y", null, xmlnsY.NamespaceName);
668 xml.WriteAttributeString(
"xmlns",
"yed", null, xmlnsYed.NamespaceName);
669 xml.WriteAttributeString(
"xsi",
"schemaLocation", null, xsiSchemaLocation);
671 for (
int i = 0; i < Properties.Count; i++)
673 var p = Properties[i];
675 p.GetKeyElement().WriteTo(xml);
678 xml.WriteStartElement(
"graph", xmlns.NamespaceName);
679 xml.WriteAttributeString(
"id",
"G");
680 xml.WriteAttributeString(
"edgedefault",
"directed");
681 xml.WriteAttributeString(
"parse.nodes", Graph.NodeCount().ToString(CultureInfo.InvariantCulture));
682 xml.WriteAttributeString(
"parse.edges", Graph.ArcCount().ToString(CultureInfo.InvariantCulture));
683 xml.WriteAttributeString(
"parse.order",
"nodesfirst");
684 DefinePropertyValues(xml, Graph);
685 foreach (var node
in Graph.Nodes())
687 xml.WriteStartElement(
"node", xmlns.NamespaceName);
688 xml.WriteAttributeString(
"id", node.Id.ToString(CultureInfo.InvariantCulture));
689 DefinePropertyValues(xml, node);
690 xml.WriteEndElement();
692 foreach (var arc
in Graph.Arcs())
694 xml.WriteStartElement(
"edge", xmlns.NamespaceName);
695 xml.WriteAttributeString(
"id", arc.Id.ToString(CultureInfo.InvariantCulture));
696 if (
Graph.IsEdge(arc)) xml.WriteAttributeString(
"directed",
"false");
697 xml.WriteAttributeString(
"source",
Graph.U(arc).Id.ToString(CultureInfo.InvariantCulture));
698 xml.WriteAttributeString(
"target",
Graph.V(arc).Id.ToString(CultureInfo.InvariantCulture));
699 DefinePropertyValues(xml, arc);
700 xml.WriteEndElement();
702 xml.WriteEndElement();
703 xml.WriteEndElement();
708 public void Save(TextWriter writer)
710 using (XmlWriter xml = XmlWriter.Create(writer))
715 public void Save(
string filename)
717 using (StreamWriter writer =
new StreamWriter(filename))