Reading and Writing Graph Structure Data Using GraphML

The yFiles for Silverlight graph visualization library supports serialization and deserialization of graphs in the GraphML file format. The GraphML file format results from the joint effort of the graph drawing community to define a common, XML-based format for exchanging graph structure data.

This section

What GraphML Looks Like

A GraphML file that shows the encoding of a simple graph is presented in Example 6.1, “GraphML representation”. The basic graph structure is encoded using the GraphML elements <graph>, <node>, <edge>, and <port>. Except the latter, each of these elements has an XML attribute id whose value is used to uniquely identify graphs, nodes, and edges within a GraphML file. The ports of a node are identified by their XML attribute name whose value needs to be unique within the containing <node> element.

XML attributes source and target which are part of the <edge> element, reference unique node IDs to indicate both source and target node of an edge. Also part of the <edge> element are XML attributes sourceport and targetport which name the respective ports that an edge connects to.

Example 6.1, “GraphML representation” also shows enhancements to the GraphML file format which are specific to yFiles for Silverlight. They describe the visual representation of a graph and are nested within the <data> element of a graph, a node, an edge, or a port.

Example 6.1. GraphML representation

<?xml version="1.0" encoding="utf-8"?>
<!--Created by yFiles for Silverlight 1.0-->
<graphml xsi:schemaLocation="http://graphml.graphdrawing.org/xmlns 
    http://www.yworks.com/xml/schema/graphml.silverlight/1.0/ygraphml.xsd"
         xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
         xmlns:ysl="http://www.yworks.com/xml/yfiles-for-silverlight/1.0/xaml"
         xmlns:y="http://www.yworks.com/xml/yfiles-common/2.0"
         xmlns:x="http://www.yworks.com/xml/yfiles-common/markup/2.0"
         xmlns="http://graphml.graphdrawing.org/xmlns">
  <key id="d0" for="node" attr.name="NodeLabels"
       y:attr.uri="http://www.yworks.com/xml/yfiles-common/2.0/NodeLabels" />
  <key id="d1" for="node" attr.name="NodeGeometry"
       y:attr.uri="http://www.yworks.com/xml/yfiles-common/2.0/NodeGeometry" />
  <key id="d2" for="node" attr.name="NodeStyle"
       y:attr.uri="http://www.yworks.com/xml/yfiles-common/2.0/NodeStyle" />
  <key id="d3" for="edge" attr.name="EdgeLabels"
       y:attr.uri="http://www.yworks.com/xml/yfiles-common/2.0/EdgeLabels" />
  <key id="d4" for="edge" attr.name="EdgeGeometry"
       y:attr.uri="http://www.yworks.com/xml/yfiles-common/2.0/EdgeGeometry" />
  <key id="d5" for="edge" attr.name="EdgeStyle"
       y:attr.uri="http://www.yworks.com/xml/yfiles-common/2.0/EdgeStyle" />
  <key id="d6" for="port" attr.name="PortLocationParameter" y:attr.uri=
       "http://www.yworks.com/xml/yfiles-common/2.0/PortLocationParameter">
    <default>
      <x:Static Member="ysl:NodeScaledPortLocationModel.NodeCenterAnchored" />
    </default>
  </key>
  <key id="d7" for="port" attr.name="PortStyle"
       y:attr.uri="http://www.yworks.com/xml/yfiles-common/2.0/PortStyle">
    <default>
      <x:Static Member="y:VoidPortStyle.Instance" />
    </default>
  </key>
  <key id="d8" for="all" attr.name="SharedData"
       y:attr.uri="http://www.yworks.com/xml/yfiles-common/2.0/SharedData" />
  <key id="d9" for="all" attr.name="UserTags"
       y:attr.uri="http://www.yworks.com/xml/yfiles-common/2.0/UserTags" />
  <data key="d8">
    <y:SharedData>
      <ysl:ShapeNodeStyle x:Key="1" Pen="{x:Static ysl:Pens.Red}"
                          Brush="#FF0C2238" Shape="Rectangle" />
    </y:SharedData>
  </data>
    <graph id="G" edgedefault="directed">
    <node id="n0">
      <data key="d2">
        <y:GraphMLReference ResourceKey="1" />
      </data>
      <data key="d1">
        <y:RectD X="-221.94999999925494" Y="-13.614999999254962"
                 Width="30" Height="30" />
      </data>
      <port name="p0" />
    </node>
    <node id="n1">
      <data key="d2">
        <y:GraphMLReference ResourceKey="1" />
      </data>
      <data key="d1">
        <y:RectD X="-360.94999999925494" Y="-134.61499999925496"
                 Width="30" Height="30" />
      </data>
      <port name="p0" />
    </node>
    <edge id="e0" source="n1" target="n0" sourceport="p0" targetport="p0">
      <data key="d5">
        <ysl:PolylineEdgeStyle
            Pen="{x:Static ysl:Pens.Black}"
            TargetArrow="{x:Static ysl:DefaultArrow.Default}"
            SourceArrow="{x:Static ysl:DefaultArrow.None}" />
      </data>
    </edge>
  </graph>
</graphml>

The GraphML file format is also described in the GraphML Primer.

Working with the GraphML File Format

Class GraphControl directly provides convenient support for (de)serializing the graph model it displays via the following methods:

More control over the serialization or deserialization is provided by class GraphMLIOHandler through the methods listed below. Note that all Read method overloads require an existing IGraph instance, which is then populated by the GraphMLIOHandler.

The code fragment in Example 6.2, “Instantiating a GraphMLIOHandler” shows how to instantiate and use a GraphMLIOHandler to write an IGraph to a GraphML-encoded file.

Example 6.2. Instantiating a GraphMLIOHandler

public void EncodeAsGraphML(IGraph graph) {
  // Instantiate a GraphML I/O handler and write the graph to file. 
  try {
    GraphMLIOHandler ioh = new GraphMLIOHandler();
    ioh.Write(graph, "MyGraphML.graphml");
  }
  catch (IOException ioEx) {
    // Something went wrong. Complain. 
  }
}

Loading and saving graphs in GraphML file format is demonstrated in tutorial demo application SimpleGraphMLDemo.

GraphML Attributes

The GraphML file format knows so-called GraphML attributes to conveniently store additional information that is associated with a graph structure. By default, this mechanism is used to store both framework-related data as well as user-defined data in a GraphML file.

A GraphML attribute consists of two complementing parts, namely its declaration and its values:

  • The declaration is a <key> element which must precede any <graph> element in a GraphML file. It comprises a unique identifier as well as scope, name, and the domain of values (i.e., the actual type) for the GraphML attribute.
  • The actual values for a GraphML attribute are specified using <data> elements which are nested within the <graphml>, <graph>, <node>, <edge>, or <port> elements in a GraphML file.

Example 6.3, “GraphML attribute declaration and actual value” shows an excerpt of a GraphML file that highlights a GraphML attribute's declaration and an actual value for a graph element.

Example 6.3. GraphML attribute declaration and actual value

<graphml ... >
  ...
  <!-- Declaration of a GraphML attribute for the geometry of edges. The value 
       for 'id' denotes a unique identifier that needs to be matched by the 
       'key' value of corresponding <data> elements. -->
  <key id="d4" for="edge" attr.name="EdgeGeometry" 
       y:attr.uri="http://www.yworks.com/xml/yfiles-common/2.0/EdgeGeometry"/>
  ...
  <graph ... >
    ...
    <edge id="e0" source="n0" target="n1" sourceport="p0" targetport="p0">
<!-- An actual value for the 'd4' GraphML attribute. Encodes the geometry of 
     the enclosing edge.
     The value of the 'key' attribute specifies which GraphML attribute 
     declaration is actually referenced. -->
      <data key="d4">
        <x:List>
          <y:Bend Location="-25,102" />
          <y:Bend Location="-104,140" />
        </x:List>
      </data>
    </edge>
    ...
  </graph>
</graphml>

yFiles for Silverlight uses several GraphML attributes for the various aspects of a graph element's visual representation, such as geometry, label, and style information. Table 6.1, “Predefined combinations for the XML attributes in the declaration of a GraphML attribute” lists the predefined combinations of values for the XML attributes in a <key> element that denote these GraphML attributes.

Note that the table omits the y:attr.uri attribute which holds a URI that results from prepending the value of the attr.name attribute with the following prefixes: http://www.yworks.com/xml/yfiles-common/2.0/, respectively http://www.yworks.com/xml/yfiles-common/2.0/folding/ for GraphML attributes related to state in a folding-enabled IGraph.

Table 6.1. Predefined combinations for the XML attributes in the declaration of a GraphML attribute

Combination of Values Description
for= "all" attr.name= "UserTags" Specifies a GraphML attribute with scope for all elements whose values encode user tags, i.e., data bound to ITagOwner.
attr.name= "SharedData" Specifies a GraphML attribute with scope for the entire contents of a GraphML file. The values encode shared object instances that can be used for multiple graph elements. For example, style information, label model parameters, or port location parameters can be shared.
for= "node" attr.name= "NodeGeometry" Specifies a GraphML attribute with node scope. The attribute's values encode the geometry of nodes, i.e., upper left corner, width, and height.
attr.name= "NodeStyle" Specifies a GraphML attribute with node scope. The attribute's values encode the style information of nodes by means of an INodeStyle instance.
attr.name= "NodeLabels" Specifies a GraphML attribute with node scope. The attribute's values encode the labels of nodes.
attr.name= "Expanded" Specifies a GraphML attribute with node scope. The attribute's values are of boolean type and encode whether a group node in a folding-enabled IGraph is expanded or not.
attr.name= "NodeViewState" Specifies a GraphML attribute with node scope. The attribute's values encode the view state information of nodes in a folding-enabled IGraph.
for= "edge" attr.name= "EdgeGeometry" Specifies a GraphML attribute with edge scope. The attribute's values encode the geometry of edges.
attr.name= "EdgeStyle" Specifies a GraphML attribute with edge scope. The attribute's values encode the style information of edges by means of an IEdgeStyle instance.
attr.name= "EdgeLabels" Specifies a GraphML attribute with edge scope. The attribute's values encode the labels of edges.
attr.name= "EdgeViewState" Specifies a GraphML attribute with edge scope. The attribute's values encode the view state information of edges in a folding-enabled IGraph.
for= "port" attr.name= "PortLocationParameter" Specifies a GraphML attribute with port scope. The attribute's values encode port location parameters.
attr.name= "PortStyle" Specifies a GraphML attribute with port scope. The attribute's values encode the style information of ports by means of an IPortStyle instance.
attr.name= "PortViewState" Specifies a GraphML attribute with port scope. The attribute's values encode the view state information of ports in a folding-enabled IGraph.

Reading and Writing Additional Data

Beyond the basic I/O support as described in the section called “Working with the GraphML File Format”, class GraphMLIOHandler also provides convenient support for both writing out and reading in additional data that is associated with a graph structure to/from GraphML attributes. Furthermore, many aspects of the serialization and deserialization process can be customized.

The following sections describe:

  • Convenience support for writing out and reading in arbitrary data using IMapper<K, V> instances as data output sources and data input targets, respectively.
  • General (de)serialization support for additional data that is associated with a graph structure.
  • Support for customizing both the serialization and deserialization of additional data that consists of user-defined data types.
  • Support for handling references to data that is defined externally, i.e., not within the GraphML file itself.

Simple vs. Structured Type Support

Both reading and writing of additional data that is of simple types (like, e.g., boolean, int, long, float, double, or string) is supported transparently. This means, an IMapper that holds long values, for example, can be (de)serialized from/to a GraphML attribute with minimal effort using the convenience functionality provided by GraphMLIOHandler.

For data consisting of structured types, the yFiles for Silverlight XAML (de)serialization infrastructure is used, i.e., reading and writing also works out-of-the-box provided that the types fulfill conformance requirements for being XAML-(de)serializable. Similarly, structured types that provide an appropriate markup extension are also supported without further setup necessary.

Namespace handling for data consisting of structured types that is written by the XAML serialization mechanism is discussed in the section called “Namespace Mapping”.

Support for reading and writing of data that consists of structured types which cannot be (de)serialized by the yFiles for Silverlight XAML (de)serialization infrastructure is provided through serialization/deserialization callbacks as explained in the section called “Custom Serialization and Deserialization”.

Information related to XAML serialization and deserialization can be found in the .NET framework's documentation. For example:

Note

Some core classes mentioned in the documents above that are specific to WPF have been reimplemented in yFiles for Silverlight. This applies especially to:

Reading and Writing Data Using IMappers as Data Holders

The GraphML framework supports reading additional data most conveniently when using IMappers to store the retrieved data. This functionality is built on top of the general serialization and deserialization support. The following convenience methods of GraphMLIOHandler enable registering IMappers as input data targets:

void AddInputMapper<TKey, TData>(
    string name, IMapper<TKey, TData> mapper)
  where TKey : class
Description Register a generic IMapper<K, V> instance for use as an input data target.
void AddInputMapper<TKey, TData>(
    string name, KeyType type, IMapper<TKey, TData> mapper,
    EventHandler<HandleDeserializationEventArgs> deserializationCallback)
  where TKey : class
Description Register a generic IMapper<K, V> instance for use as an input data target. A custom event handler delegate for deserialization can be specified.

The IMapper<K, V> instances bind the data stored in GraphML attributes to their corresponding graph elements. The specified name must correspond to the attr.name of the GraphML attribute's key definition.

The following fragment shows how to register a mapper as input target for a GraphML attribute with node scope that stores long values.

Example 6.4. Adding a GraphML input attribute to GraphMLIOHandler

GraphMLIOHandler ioh = new GraphMLIOHandler();
// Create a mapper.
IMapper<INode, long> nodeMapper = new DictionaryMapper<INode, long>();

// Register the mapper with the GraphML I/O handler.
// The deserializer will be looking for data that has attr.name "nodeAttr".
ioh.AddInputMapper<INode, long>("nodeAttr", nodeMapper);

As an alternative to registering already instantiated IMapper instances as the input targets, GraphMLIOHandler also supports registering IMapper "futures" using generic class Future<T>. Basically, "futures" means that IMapper instances are created lazily depending on whether there is actually a GraphML attribute with a matching attr.name specified in the GraphML file that is read. The following methods can be used for declaring IMapper "futures" when reading GraphML:

To write data from an IMapper to a GraphML attribute, GraphMLIOHandler provides a set of methods to register the IMapper instance as an output data source that can be used analogously to the attribute input methods.

General (De)Serialization Support

The general scheme for serialization and deserialization of data types uses so-called output handlers and input handlers. These handlers are responsible for writing out, respectively reading in (structured) data. Event handlers for registering both output handlers and input handlers can be attached to the QueryOutputHandlers and QueryInputHandlers events, respectively. They are invoked by GraphMLIOHandler dynamically, i.e., at the time of writing or reading.

Example 6.5. Attaching output handlers and input handlers to a GraphMLIOHandler instance

GraphMLIOHandler ioh = new GraphMLIOHandler();
ioh.QueryOutputHandlers +=
  delegate(object sender, QueryOutputHandlersEventArgs args) {
    args.AddOutputHandler(MyGetCustomEdgeOutputHandler(), KeyScope.Edge);
  };

ioh.QueryInputHandlers +=
  delegate(object sender, QueryInputHandlersEventArgs args) {
    String tag = GraphMLIOHandler.GetKeyName(args.KeyDefinition);
    if (args.Handled || !tag.StartsWith("my-custom-edge-data")) {
      return;
    }
    args.AddInputHandler(MyGetCustomEdgeInputHandler());
    args.Handled = true;
  };

Output handlers and input handlers for data types are implementations of interfaces IOutputHandler and IInputHandler, respectively. For both interfaces there are abstract implementations available which serve as convenient base classes:

The predefined generic classes ComplexMapperOutputHandler<TKey, TValue> and ComplexMapperInputHandler<TKey, TValue> provide the default support for writing and reading structured data that is held by IMapper instances.

Example 6.6, “Using data that is not held by an IMapper” shows how structured data that is not held by an IMapper can still be used in conjunction with generic class ComplexMapperOutputHandler by means of the Mappers helper class.

Example 6.6. Using data that is not held by an IMapper

GraphMLIOHandler ioh = new GraphMLIOHandler();
ioh.QueryOutputHandlers +=
  delegate(object sender, QueryOutputHandlersEventArgs args) {
    ComplexMapperOutputHandler<IEdge, MyCustomData> mapperOH =
      new ComplexMapperOutputHandler<IEdge, MyCustomData>("my-edge-data");

    // Get the data from somewhere and "convert" it to IMapper format.
    mapperOH.Mapper = Mappers.CreateMapper<IEdge, MyCustomData>(
      key => MyGetCustomDataFromSomewhere(key));

    args.AddOutputHandler(mapperOH, KeyScope.Edge);
  };

Custom Serialization and Deserialization

The default support for writing and reading structured data relies on the .NET framework's XAML reader/writer infrastructure. Specialized serialization and deserialization logic for structured data that is beyond this infrastructure or cannot be realized through markup extensions, for example, can be provided by means of event handlers.

Generic class ComplexMapperOutputHandler<TKey, TValue> enables custom serialization logic through the Serializer property. It can be used to attach an event handler specifically for the structured data that is held by an IMapper. Similarly, generic class ComplexMapperInputHandler<TKey, TValue> enables custom deserialization logic for an IMapper's data through the Deserializer property.

Example 6.7, “Custom serialization logic for structured data from an IMapper” shows custom serialization for data held in an IMapper.

Example 6.7. Custom serialization logic for structured data from an IMapper

GraphMLIOHandler ioh = new GraphMLIOHandler();
ioh.QueryOutputHandlers +=
  delegate(object sender, QueryOutputHandlersEventArgs args) {
    ComplexMapperOutputHandler<IEdge, MyTextHolder> mapperOH =
      new ComplexMapperOutputHandler<IEdge, MyTextHolder>("my-edge-data");

    // Get the IMapper from the graph's mapper registry.
    IMapperRegistry mapperRegistry = args.Context.Graph.MapperRegistry;
    mapperOH.Mapper =
      mapperRegistry.GetMapper<IEdge, MyTextHolder>("my-edge-data-imapper");

    // Specify the custom serialization logic.
    mapperOH.Serializer =
      delegate(object serialSender, HandleSerializationEventArgs hsArgs) {
        // Only serialize items that are of the specific type.
        if (hsArgs.Item is MyTextHolder ||
            hsArgs.SourceType == typeof (MyTextHolder)) {
          MyTextHolder myItem = hsArgs.Item as MyTextHolder;
          if (myItem != null) {
            IXmlWriter writer = hsArgs.Writer;
            writer.WriteStartElement("MyReversedString", "MyNamespace");
            writer.WriteCData(MyGetReversedString(myItem.Text));
            writer.WriteEndElement();
            // Signal that this item is serialized.
            hsArgs.Handled = true;
          }
        }
      };
    args.AddOutputHandler(mapperOH, KeyScope.Edge);
  };

Example 6.8, “Custom deserialization logic for structured data” shows custom deserialization logic that corresponds to the serialization above.

Example 6.8. Custom deserialization logic for structured data

// 'ioh' is of type yWorks.yFiles.GraphML.GraphMLIOHandler.

ioh.QueryInputHandlers +=
  // Register a delegate that is called when the <key> definitions of the 
  // GraphML attributes in a GraphML file are parsed.
  delegate(object sender, QueryInputHandlersEventArgs args) {
    String tag = GraphMLIOHandler.GetKeyName(args.KeyDefinition);
    // We are interested in the 'my-edge-data' GraphML attribute only. The
    // <key> definitions for other GraphML attributes are ignored.
    if (args.Handled || !tag.StartsWith("my-edge-data")) {
      return;
    }
    // Create and register an input handler that can read our structured data.
    // The delegate is called for each <data> element that holds a value of 
    // the GraphML attribute.
    ComplexMapperInputHandler<IEdge, MyTextHolder> mapperIH =
      new ComplexMapperInputHandler<IEdge, MyTextHolder>(
        delegate(object deserialSender,
                 HandleDeserializationEventArgs hdArgs) {
          string text =
            MyGetReversedString(((XElement) hdArgs.XmlNode).Value);
          System.Console.WriteLine(text);
          hdArgs.Result = new MyTextHolder(text);
        });
    IMapperRegistry mapperRegistry = args.Context.Graph.MapperRegistry;
    mapperIH.Mapper =
      mapperRegistry.GetMapper<IEdge, MyTextHolder>("my-edge-data-imapper");
    args.AddInputHandler(mapperIH);
    args.Handled = true;
  };

In addition, the HandleSerialization and HandleDeserialization events available with GraphMLIOHandler can also be used to attach event handlers that provide custom (de)serialization logic. These event handlers can be used to realize support for structured types that are used by multiple IMappers, for example, or to provide general support for structured types in nested XML content of GraphML attribute data.

Reference Handling

The yFiles for Silverlight GraphML implementation transparently supports sharing of data that is referenced from multiple places. For example, the XML content that defines the style for a node is written only once instead of for each node that uses the same style. In the node's <data> element then, there is only a reference into the shared data section of the GraphML provided. Example 6.9, “Reference into the shared data section” shows the relevant parts that present referencing shared referenced data in a GraphML file.

Example 6.9. Reference into the shared data section

<?xml version="1.0" encoding="utf-8"?>
<!--Created by yFiles for Silverlight 1.0-->
<graphml ... >
  ...
// The key definition of the shared data section in a GraphML file.
  <key id="d8" for="all" attr.name="SharedData"
       y:attr.uri="http://www.yworks.com/xml/yfiles-common/2.0/SharedData" />
  ...
// The shared data section.
  <data key="d8">
// An entry in the shared data section: style data that is shared between graph
// elements. The root element of the shared content is added a new XML
// attribute: 'x:Key'
// The value of this attribute is a unique ID that needs to be matched by any
// 'ResourceKey' values later on in order to share the data.
    <y:SharedData>
      <ysl:ShapeNodeStyle x:Key="1" Pen="{x:Static ysl:Pens.Red}"
                          Brush="#FF0C2238" Shape="Rectangle" />
    </y:SharedData>
  </data>
  ...
  <graph id="G" edgedefault="directed">
    <node id="n1">
      <data key="d2">
// A reference into the shared data section. The value of the 'ResourceKey'
// attribute specifies the ID of the entry that is actually referenced.
        <y:GraphMLReference ResourceKey="1" />
      </data>
      ...
    </node>
    ...
  </graph>
</graphml>

Sharing of referenced data is available for framework data as well as user-defined data. It is controlled by the WriteSharedReferences property. Fine-grained control over the sharing behavior for specific data can be achieved by annotating properties using the GraphML attribute as shown in Example 6.10, “Annotating explicit reference sharing behavior for specific data”.

Example 6.10. Annotating explicit reference sharing behavior for specific data

// Excluding the property from reference sharing.
[GraphML(Shareable = GraphMLSharingMode.Never)]
public string MyComment { get; set; }

Instead of embedding referenced data into a GraphML file, it is also possible to only add so-called external references by specifying symbolic names. To this end, event handlers that provide the symbolic names can be attached to the QueryReferenceId event as shown in Example 6.11, “Writing an external reference using a symbolic name”.

Example 6.11. Writing an external reference using a symbolic name

GraphMLIOHandler ioh = new GraphMLIOHandler();
ioh.QueryReferenceId +=
    delegate(object sender, QueryReferenceIdEventArgs args) {
      // If the current object is the same as the default node style, then write
      // "DefaultNodeStyle" instead.
      if (args.Value == args.Context.Graph.NodeDefaults.Style) {
        args.ReferenceId = "DefaultNodeStyle";
      }
    };

The symbolic name is specified using the ReferenceId property provided by the event arguments type that is handed over to the event handler. It is then used in the <data> element as shown in Example 6.12, “External reference in the <data> element”.

Example 6.12. External reference in the <data> element

<node id="n1">
  <data key="d2">
// An external reference. The value of the 'ResourceKey' attribute is a
// user-defined symbolic name.
    <y:GraphMLReference ResourceKey="DefaultNodeStyle" />
  </data>
  ...
</node>

When reading in a GraphML file, an application can be notified of external references by attaching event handlers to the ResolveReference event. This event is triggered for references that could not be resolved (by internal references), which is especially true for external references.

Example 6.13. Resolving an external reference using a symbolic name

// 'ioh' is of type yWorks.yFiles.GraphML.GraphMLIOHandler.

ioh.ResolveReference +=
    delegate(object sender, ResolveReferenceEventArgs args) {
      if (args.ReferenceId.Equals("DefaultNodeStyle")) {
        // If we encounter a "DefaultNodeStyle" reference, retrieve an instance
        // from the graph's NodeDefaults.
        args.Value = args.Context.Graph.NodeDefaults.GetStyleInstance();
      }
    };
Namespace Mapping

Custom data consisting of structured types that is serialized by the default XAML serialization support can be given a custom XML namespace by means of a namespace mapping. The mapping from CLR namespace (which would be used otherwise when writing out the data) to an XML namespace is expressed using an attribute annotation.

The following example shows how attribute annotations to define an XML namespace mapping are used in the SimpleCustomStyleWindow tutorial demo application:

Example 6.14. Attribute annotation for XML namespace mapping

[assembly:XmlnsDefinition(
    "http://www.yworks.com/yFilesForSilverlight/demos/SimpleCustomStyle/2.0", 
    "Demo.yFiles.Graph.SimpleCustomStyle")]
[assembly:XmlnsPrefix(
    "http://www.yworks.com/yFilesForSilverlight/demos/SimpleCustomStyle/2.0", 
    "demo")]

namespace Demo.yFiles.Graph.SimpleCustomStyle { ... }

The resulting GraphML looks in parts like so:

Example 6.15. GraphML using a custom XML namespace and prefix

<?xml version="1.0" encoding="utf-8"?>
<!--Created by yFiles for Silverlight 1.0-->
<graphml
    xmlns:demo="http://www.yworks.com/silverlight/examples/SimpleCustomStyle"

    xsi:schemaLocation="http://graphml.graphdrawing.org/xmlns
          http://www.yworks.com/xml/schema/graphml.silverlight/1.0/ygraphml.xsd"
    xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
    xmlns:ysl="http://www.yworks.com/xml/yfiles-for-silverlight/1.0/xaml"
    xmlns:y="http://www.yworks.com/xml/yfiles-common/2.0"
    xmlns:x="http://www.yworks.com/xml/yfiles-common/markup/2.0"
    xmlns="http://graphml.graphdrawing.org/xmlns">
...
<key id="d9" attr.name="SharedData"
     y:attr.uri="http://www.yworks.com/xml/yfiles-common/2.0/SharedData" />
<data key="d9">
  <y:SharedData>
    <demo:MySimpleNodeStyle x:Key="1" />
    <demo:MySimpleLabelStyle x:Key="2" />
    <demo:MySimpleEdgeStyle x:Key="3">
      <demo:MySimpleEdgeStyle.Arrows>
        <demo:MySimpleArrow />
      </demo:MySimpleEdgeStyle.Arrows>
    </demo:MySimpleEdgeStyle>
  </y:SharedData>
</data>
...
</graphml>

Tutorial Demo Code

For examples how customized writing and parsing logic can be provided, please see the following tutorial demo applications: