Customizing the GraphML Extension Mechanism

The GraphML default extension mechanism can be customized to enable GraphML attributes that hold arbitrarily complex data. The basic technique to enhance the extension mechanism is to define a new XML attribute with the <key> element and nest user-defined XML elements inside the <data> element.

The newly introduced XML attribute plays a crucial role when reading GraphML file format: All <key> elements available in a file are parsed early on, and their respective set of XML attributes is handed over for inspection to any registered parser. Parser logic that corresponds to a GraphML attribute declaration then signals acceptance based on the outcome of this inspection. Subsequently, when the <data> elements of the file are parsed, the GraphML attribute look-up mechanism is used to find the matching unique ID of a <key> element, which in turn selects the corresponding parser logic that handles the contents of the <data> element.

The yFiles FLEX GraphML I/O classes evaluate the attr.name attribute to have the GraphML parser logic branch to code that handles complex data specific to yFiles FLEX such as that relating to the visual representation of a IGraph from a GraphML file.

yFiles FLEX uses separate GraphML data attributes for the various aspects of a graph element's visual representation, such as layout, label, and style information.

As listed in Table 4.3, “Predefined combinations for XML attributes for and attr.name” there is a set of values predefined for attr.name, where each is valid only in conjunction with appropriate values for XML attributes for and attr.type.

Table 4.3. Predefined combinations for XML attributes for and attr.name

Combination of Values Description
for= "node" | "edge" | "port" attr.name= "geometry" attr.type= "complex" Used to declare a GraphML attribute with either node, edge, or port scope. The attribute's values encode the geometry information of the respective graph element.
for= "node" | "edge" attr.name= "style" attr.type= "complex" Used to declare a GraphML attribute with either node or edge scope. The attribute's values encode the style information of the graph element, which is described with an INodeStyle or IEdgeStyle instance.
for= "node" | "edge" attr.name= "labels" attr.type= "complex" Used to declare a GraphML attribute with either node or edge scope. The attribute's values encode the labels of the graph element.

Example 4.4, “Predefined yFiles FLEX-specific GraphML attributes” lists all predefined GraphML data attributes. The declaration of the GraphML attributes that hold all data relating to the visual representation of nodes and edges is shown in Example 4.1, “Abbreviated yFiles.NET/yFiles FLEX GraphML representation” and Example 4.2, “Abbreviated yFiles Java GraphML representation”.

Example 4.4. Predefined yFiles FLEX-specific GraphML attributes

<!-- Node layout data. -->
<key id="d0" for="node" attr.name="geometry" attr.type="complex" />
<!-- Node label data. -->
<key id="d1" for="node" attr.name="labels" attr.type="complex" />
<!-- Node style data. -->
<key id="d2" for="node" attr.name="style" attr.type="complex" />

<!-- Edge layout data. -->
<key id="d3" for="edge" attr.name="geometry" attr.type="complex" />
<!-- Edge label data. -->
<key id="d4" for="edge" attr.name="labels" attr.type="complex" />
<!-- Edge style data. -->
<key id="d5" for="edge" attr.name="style" attr.type="complex" />

<!-- Port layout data. -->
<key id="d6" for="port" attr.name="geometry" attr.type="complex" />

The various predefined data attributes for a graph element determine the corresponding aspects of this element's visual appearance. Example 4.5, “Edge-related data” shows the entire encoding for an IEdge.

Example 4.5. Edge-related data

<!-- Declares an edge between nodes n0 and n1 that docks to the port p0 at -->
<!-- both nodes. -->
<edge id="e0" source="n0" target="n1" sourceport="p0" targetport="p0">
  <data key="d3">
<!-- Encodes the edge geometry, in this case a list of control points -->
<!-- (bends). -->
    <y:Path>
      <y:Point x="51" y="416"/>
      <y:Point x="196" y="558"/>
    </y:Path>
  </data>
<!-- Encodes the labels, a list of label elements. -->            
  <data key="d4">
    <y:Labels>
<!-- The first label... -->
      <y:Label>
<!-- ...uses a specific style -->
        <y:ISimpleLabelStyle>
          <y:Font family="Serif" points="12" style="Regular"/>
          <y:Brush name="SolidBrush" color="#ff000000"/>
        </y:ISimpleLabelStyle>
<!-- ...and uses a rotating label model. -->
        <y:RotatingEdgeLabelModel ratio="0.5">
          <y:ModelState angle="0" />
        </y:RotatingEdgeLabelModel>EdgeLabel</y:Label>            
<!-- The second label. -->
      <y:Label>
        <y:ISimpleLabelStyle>
          <y:Font family="Serif" points="12" style="Regular"/>
          <y:Brush name="SolidBrush" color="#ff000000"/>
        </y:ISimpleLabelStyle>
        <y:RotatingEdgeLabelModel ratio="0.5">
          <y:ModelState angle="0" />
        </y:RotatingEdgeLabelModel>Second EdgeLabel</y:Label>
    </y:Labels>
  </data>
<!-- Encodes the style information, in this case an IPolylineEdgeStyle -->
<!-- instance. -->                  
  <data key="d5">
    <y:IPolylineEdgeStyle>
      <y:Pen name="SolidColor" color="#990000ff" width="2"/>
<!-- A Spearhead shaped source arrow -->
      <y:Arrow at="source" type="Spearhead" cropLength="5">
        <y:Pen name="SolidColor" color="#99ff0000" width="2"/>
        <y:Brush name="SolidBrush" color="#99ffcc00"/>
      </y:Arrow>
<!-- A default shaped target arrow -->
      <y:Arrow at="target" type="Default" cropLength="0">
        <y:Pen name="SolidColor" color="#ff000000" width="1"/>
        <y:Brush name="SolidBrush" color="#ff000000"/>
      </y:Arrow>
     </y:IPolylineEdgeStyle>
  </data>
</edge>