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 T
this[
object key]
186 TryGetValue(key, out result);
191 public override void ReadData(XElement x,
object key)
196 if (key == null) HasDefaultValue =
false;
else Values.Remove(key);
201 T value = ReadValue(x);
204 HasDefaultValue =
true;
205 DefaultValue = value;
207 else Values[key] = value;
211 public override XElement WriteData(
object key)
215 return HasDefaultValue ? WriteValue(DefaultValue) : null;
220 if (!Values.TryGetValue(key, out value))
return null;
221 return WriteValue(value);
229 protected abstract T ReadValue(XElement x);
232 protected abstract XElement WriteValue(T value);
262 public sealed
class StandardProperty<T> : DictionaryProperty<T>
265 private static readonly
StandardType Type = ParseType(typeof(T));
267 private static readonly
string TypeString = TypeToGraphML(Type);
269 public StandardProperty()
275 internal StandardProperty(XElement xKey)
278 var attrType = xKey.Attribute(
"attr.type");
279 if (attrType == null || attrType.Value != TypeString)
280 throw new ArgumentException(
"Key not compatible with property.");
281 LoadFromKeyElement(xKey);
293 throw new ArgumentException(
"Invalid type for a standard GraphML property.");
306 default:
return "string";
310 private static object ParseValue(
string value)
315 case StandardType.Double:
return double.Parse(value, CultureInfo.InvariantCulture);
316 case StandardType.Float:
return float.Parse(value, CultureInfo.InvariantCulture);
317 case StandardType.Int:
return int.Parse(value, CultureInfo.InvariantCulture);
318 case StandardType.Long:
return long.Parse(value, CultureInfo.InvariantCulture);
319 default:
return value;
323 private static string ValueToGraphML(
object value)
327 case StandardType.Bool:
return (
bool)value ?
"true" :
"false";
328 case StandardType.Double:
return ((
double)value).ToString(CultureInfo.InvariantCulture);
329 case StandardType.Float:
return ((
float)value).ToString(CultureInfo.InvariantCulture);
330 case StandardType.Int:
return ((
int)value).ToString(CultureInfo.InvariantCulture);
331 case StandardType.Long:
return ((
long)value).ToString(CultureInfo.InvariantCulture);
332 default:
return value.ToString();
336 public override XElement GetKeyElement()
338 XElement x = base.GetKeyElement();
339 x.SetAttributeValue(
"attr.type", TypeString);
343 protected override T ReadValue(XElement x)
345 return (T)ParseValue(x.Value);
348 protected override XElement WriteValue(T value)
350 return new XElement(
"dummy", ValueToGraphML(value));
367 public double X {
get;
set; }
369 public double Y {
get;
set; }
371 public double Width {
get;
set; }
373 public double Height {
get;
set; }
384 private readonly
string[] nodeShapeToString = {
"rectangle",
"roundrectangle",
"ellipse",
"parallelogram",
385 "hexagon",
"triangle",
"rectangle3d",
"octagon",
386 "diamond",
"trapezoid",
"trapezoid2"};
391 return (
NodeShape)(Math.Max(0, Array.IndexOf(nodeShapeToString, s)));
395 private string ShapeToGraphML(
NodeShape shape)
397 return nodeShapeToString[(int)shape];
403 XElement xGeometry = Utils.ElementLocal(xData,
"Geometry");
404 if (xGeometry != null)
406 X =
double.Parse(xGeometry.Attribute(
"x").Value, CultureInfo.InvariantCulture);
407 Y =
double.Parse(xGeometry.Attribute(
"y").Value, CultureInfo.InvariantCulture);
408 Width =
double.Parse(xGeometry.Attribute(
"width").Value, CultureInfo.InvariantCulture);
409 Height =
double.Parse(xGeometry.Attribute(
"height").Value, CultureInfo.InvariantCulture);
411 XElement xShape = Utils.ElementLocal(xData,
"Shape");
413 Shape = ParseShape(xShape.Attribute(
"type").Value);
417 public XElement ToXml()
419 return new XElement(
"dummy",
422 new XAttribute(
"x", X.ToString(CultureInfo.InvariantCulture)),
423 new XAttribute(
"y", Y.ToString(CultureInfo.InvariantCulture)),
424 new XAttribute(
"width", Width.ToString(CultureInfo.InvariantCulture)),
425 new XAttribute(
"height", Height.ToString(CultureInfo.InvariantCulture))),
427 new XAttribute(
"type", ShapeToGraphML(Shape)))
432 public override string ToString()
434 return ToXml().ToString();
468 var attrYFilesType = xKey.Attribute(
"yfiles.type");
469 if (attrYFilesType == null || attrYFilesType.Value !=
"nodegraphics")
470 throw new ArgumentException(
"Key not compatible with property.");
471 LoadFromKeyElement(xKey);
474 public override XElement GetKeyElement()
476 XElement x = base.GetKeyElement();
477 x.SetAttributeValue(
"yfiles.type",
"nodegraphics");
488 return value.
ToXml();
539 internal static readonly XNamespace xmlns =
"http://graphml.graphdrawing.org/xmlns";
540 private static readonly XNamespace xmlnsXsi =
"http://www.w3.org/2001/XMLSchema-instance";
541 internal static readonly XNamespace xmlnsY =
"http://www.yworks.com/xml/graphml";
542 private static readonly XNamespace xmlnsYed =
"http://www.yworks.com/xml/yed/3";
543 private const string xsiSchemaLocation =
"http://graphml.graphdrawing.org/xmlns\n" +
544 "http://graphml.graphdrawing.org/xmlns/1.0/graphml.xsd";
554 public Dictionary<Node,string> NodeId {
get;
set; }
557 public Dictionary<Arc, string> ArcId {
get;
set; }
559 public IList<GraphMLProperty> Properties {
get;
private set; }
561 private readonly List<Func<XElement, GraphMLProperty>> PropertyLoaders;
565 Properties =
new List<GraphMLProperty>();
566 PropertyLoaders =
new List<Func<XElement, GraphMLProperty>>
568 x =>
new StandardProperty<bool>(x),
569 x =>
new StandardProperty<double>(x),
570 x =>
new StandardProperty<float>(x),
571 x =>
new StandardProperty<int>(x),
572 x =>
new StandardProperty<long>(x),
573 x =>
new StandardProperty<string>(x),
587 public void RegisterPropertyLoader(Func<XElement, GraphMLProperty> loader)
589 PropertyLoaders.Add(loader);
592 private static void ReadProperties(Dictionary<string, GraphMLProperty> propertyById, XElement x,
object obj)
594 foreach (var xData
in Utils.ElementsLocal(x,
"data"))
597 if (propertyById.TryGetValue(xData.Attribute(
"key").Value, out p))
603 public void Load(XDocument doc)
608 buildableGraph.
Clear();
609 XElement xGraphML = doc.Root;
613 Dictionary<string, GraphMLProperty> propertyById =
new Dictionary<string, GraphMLProperty>();
614 foreach (var xKey
in Utils.ElementsLocal(xGraphML,
"key"))
616 foreach (var handler
in PropertyLoaders)
622 propertyById[p.
Id] = p;
625 catch (ArgumentException) { }
630 XElement xGraph = Utils.ElementLocal(xGraphML,
"graph");
631 Directedness defaultDirectedness = (xGraph.Attribute(
"edgedefault").Value ==
"directed" ?
633 ReadProperties(propertyById, xGraph,
Graph);
635 NodeId =
new Dictionary<Node, string>();
636 Dictionary<string, Node> nodeById =
new Dictionary<string, Node>();
637 foreach (var xNode
in Utils.ElementsLocal(xGraph,
"node"))
639 Node node = buildableGraph.AddNode();
640 string id = xNode.Attribute(
"id").Value;
643 ReadProperties(propertyById, xNode, node);
646 ArcId =
new Dictionary<Arc, string>();
647 foreach (var xArc
in Utils.ElementsLocal(xGraph,
"edge"))
649 Node u = nodeById[xArc.Attribute(
"source").Value];
650 Node v = nodeById[xArc.Attribute(
"target").Value];
653 XAttribute dirAttr = xArc.Attribute(
"directed");
656 Arc arc = buildableGraph.AddArc(u, v, dir);
657 XAttribute xId = xArc.Attribute(
"id");
659 ArcId[arc] = xId.Value;
660 ReadProperties(propertyById, xArc, arc);
665 public void Load(XmlReader xml)
667 XDocument doc = XDocument.Load(xml);
673 public void Load(TextReader reader)
675 using (XmlReader xml = XmlReader.Create(reader))
680 public void Load(
string filename)
682 using (StreamReader reader =
new StreamReader(filename))
686 private void DefinePropertyValues(XmlWriter xml,
object obj)
688 foreach (var p
in Properties)
690 XElement x = p.WriteData(obj);
691 if (x == null)
continue;
693 x.SetAttributeValue(
"key", p.Id);
702 public void AddStandardNodeProperty<T>(
string name, Func<Node,T> getValueForNode)
707 foreach (var node
in Graph.Nodes())
708 prop.Values[node] = getValueForNode(node);
709 Properties.Add(prop);
716 public void AddStandardArcProperty<T>(
string name, Func<Arc, T> getValueForArc)
721 foreach (var arc
in Graph.Arcs())
722 prop.Values[arc] = getValueForArc(arc);
723 Properties.Add(prop);
727 private void Save(XmlWriter xml)
729 xml.WriteStartDocument();
730 xml.WriteStartElement(
"graphml", xmlns.NamespaceName);
731 xml.WriteAttributeString(
"xmlns",
"xsi", null, xmlnsXsi.NamespaceName);
732 xml.WriteAttributeString(
"xmlns",
"y", null, xmlnsY.NamespaceName);
733 xml.WriteAttributeString(
"xmlns",
"yed", null, xmlnsYed.NamespaceName);
734 xml.WriteAttributeString(
"xsi",
"schemaLocation", null, xsiSchemaLocation);
736 for (
int i = 0; i < Properties.Count; i++)
738 var p = Properties[i];
740 p.GetKeyElement().WriteTo(xml);
743 xml.WriteStartElement(
"graph", xmlns.NamespaceName);
744 xml.WriteAttributeString(
"id",
"G");
745 xml.WriteAttributeString(
"edgedefault",
"directed");
746 xml.WriteAttributeString(
"parse.nodes", Graph.NodeCount().ToString(CultureInfo.InvariantCulture));
747 xml.WriteAttributeString(
"parse.edges", Graph.ArcCount().ToString(CultureInfo.InvariantCulture));
748 xml.WriteAttributeString(
"parse.order",
"nodesfirst");
749 DefinePropertyValues(xml, Graph);
751 Dictionary<string, Node> nodeById =
new Dictionary<string, Node>();
753 NodeId =
new Dictionary<Node,string>();
754 foreach (var kv
in NodeId)
756 if (nodeById.ContainsKey(kv.Value))
757 throw new Exception(
"Duplicate node id " + kv.Value);
758 nodeById[kv.Value] = kv.Key;
760 foreach (var node
in Graph.Nodes())
763 NodeId.TryGetValue(node, out
id);
766 id = node.Id.ToString(CultureInfo.InvariantCulture);
767 while (nodeById.ContainsKey(
id))
773 xml.WriteStartElement(
"node", xmlns.NamespaceName);
774 xml.WriteAttributeString(
"id",
id);
775 DefinePropertyValues(xml, node);
776 xml.WriteEndElement();
779 foreach (var arc
in Graph.Arcs())
783 ArcId.TryGetValue(arc, out
id);
787 xml.WriteStartElement(
"edge", xmlns.NamespaceName);
788 if (
id != null) xml.WriteAttributeString(
"id",
id);
789 if (
Graph.IsEdge(arc)) xml.WriteAttributeString(
"directed",
"false");
790 xml.WriteAttributeString(
"source", NodeId[
Graph.U(arc)]);
791 xml.WriteAttributeString(
"target", NodeId[
Graph.V(arc)]);
792 DefinePropertyValues(xml, arc);
793 xml.WriteEndElement();
796 xml.WriteEndElement();
797 xml.WriteEndElement();
802 public void Save(TextWriter writer)
804 using (XmlWriter xml = XmlWriter.Create(writer))
809 public void Save(
string filename)
811 using (StreamWriter writer =
new StreamWriter(filename))