The yFiles WPF 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
A GraphML file that shows the encoding of a simple graph is presented in Example 4.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 4.1, “GraphML representation” also shows enhancements to the GraphML file format which are specific to yFiles WPF. 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 4.1. GraphML representation
<?xml version="1.0" encoding="utf-8"?>
<!--Created by yFiles WPF 2.1-->
<graphml xsi:schemaLocation="http://graphml.graphdrawing.org/xmlns
http://www.yworks.com/xml/schema/graphml.wpf/2.0/ygraphml.xsd"
xmlns:ywpf="http://www.yworks.com/xml/yfiles-wpf/2.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:av="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
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="ywpf: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" />
<data key="d8">
<y:SharedData>
<ywpf:ShapeNodeStyle x:Key="1" Pen="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">
<ywpf:PolylineEdgeStyle TargetArrow="Default" SourceArrow="None"
Pen="Black" />
</data>
</edge>
</graph>
</graphml>
The GraphML file format is also described in the GraphML Primer.
Class GraphControl
directly provides
convenient support for (de)serializing the graph model it displays via the following
methods:
void ImportFromGraphML(string filename) |
|
| Description | Methods for reading in a graph in GraphML into the GraphControl. |
void ExportToGraphML(string fileName) |
|
| Description | Methods for writing out the GraphControl's graph to a GraphML file. |
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.
void Read(IGraph graph, string filename) |
|
| Description | Populating the given IGraph. |
void Write(IGraph graph, string filename) |
|
| Description | Writing the given IGraph. |
The code fragment in Example 4.2, “Instantiating a GraphMLIOHandler” shows how to instantiate and use a GraphMLIOHandler to write an IGraph to a GraphML-encoded file.
Example 4.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.
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:
Example 4.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 4.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 WPF uses several GraphML attributes for the various aspects of a graph element's visual representation, such as geometry, label, and style information. Table 4.2, “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 4.2. 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 |
|
| 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 |
|
| 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 |
|
| 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. | |
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:
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 WPF framework's XAML reader/writer infrastructure is used, i.e., reading and writing also works out-of-the-box provided that the types fulfill the 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 WPF framework's XAML reader/writer 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:
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 4.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:
Future<IMapper<TKey, TData>> AddInputMapperFuture<TKey, TData>(string name) where TKey : class |
|
| Description | Register an IMapper<K, V> "future" for use as an input data target. |
Future<IMapper<TKey, TData>> AddRegistryInputMapper<TKey, TData>(string name) where TKey : class |
|
| Description | Use an IMapper<K, V> "future" that will be registered in the graph's IMapperRegistry. |
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.
void AddOutputMapper<TModelItem, TValue>( string name, IMapper<TModelItem, TValue> mapper) where TModelItem : class |
|
| Description | Register a generic IMapper<K, V> instance for use as an input data source. |
void AddOutputMapper<TModelItem, TValue>( string name, IMapper<TModelItem, TValue> mapper, EventHandler<HandleSerializationEventArgs> serializationCallback, KeyType declaredKeyType) where TModelItem : class |
|
| Description | Register a generic IMapper<K, V> instance for use as an input data source. A custom event handler delegate for deserialization can be specified. |
void AddRegistryOutputMapper(string name, object tag) |
|
| Description | Use an IMapper<K, V> that has been registered in the graph's IMapperRegistry. |
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 4.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 4.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 4.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);
};
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 4.7, “Custom serialization logic for structured data from an IMapper” shows custom serialization for data held in an IMapper.
Example 4.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 4.8, “Custom deserialization logic for structured data” shows custom deserialization logic that corresponds to the serialization above.
Example 4.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(((XmlElement)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.
The yFiles WPF 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 4.9, “Reference into the shared data section” shows the relevant parts that present referencing shared referenced data in a GraphML file.
Example 4.9. Reference into the shared data section
<?xml version="1.0" encoding="utf-8"?>
<!--Created by yFiles WPF 2.1-->
<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>
<ywpf:ShapeNodeStyle x:Key="1" Pen="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 4.10, “Annotating explicit reference sharing behavior for specific data”.
Example 4.10. Annotating explicit reference sharing behavior for specific data
// Excluding the property from reference sharing.
[GraphML(Shareable = GraphMLSharingMode.Never)]
public string MyComment { ... }
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 4.11, “Writing an external reference using a symbolic name”.
Example 4.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 4.12, “External reference in the <data> element”.
Example 4.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 4.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();
}
};
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 4.14. Attribute annotation for XML namespace mapping
[assembly:XmlnsDefinition(
"http://www.yworks.com/yFilesWPF/demos/SimpleCustomStyle/1.0",
"Demo.yFiles.Graph.SimpleCustomStyle")]
[assembly:XmlnsPrefix(
"http://www.yworks.com/yFilesWPF/demos/SimpleCustomStyle/1.0", "demo")]
namespace Demo.yFiles.Graph.SimpleCustomStyle { ... }
The resulting GraphML looks in parts like so:
Example 4.15. GraphML using a custom XML namespace and prefix
<?xml version="1.0" encoding="utf-8"?>
<!--Created by yFiles WPF 2.1-->
<graphml
xmlns:demo="http://www.yworks.com/yFilesWPF/demos/SimpleCustomStyle/1.0"
xmlns:x="http://www.yworks.com/xml/yfiles-common/markup/2.0"
xmlns:y="http://www.yworks.com/xml/yfiles-common/2.0"
xmlns:ywpf="http://www.yworks.com/xml/yfiles-wpf/2.0/xaml"
xmlns:wpf="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xsi:schemaLocation="http://graphml.graphdrawing.org/xmlns
http://www.yworks.com/xml/schema/graphml.net/4.0/ygraphml.xsd"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
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>
For examples how customized writing and parsing logic can be provided, please see the following tutorial demo applications:
|
Copyright ©2008-2011, yWorks GmbH. All rights reserved. |