///
import { Parser } from 'xml2js';
export interface AttributeMap {
[key: string]: any;
}
export abstract class GraphElement {
private _id: string;
private _attributes: AttributeMap;
public get id(): string {
return this._id;
}
public set id(id: string) {
this._id = id;
}
public get attributes(): AttributeMap {
return this._attributes;
}
public set attributes(attributes: AttributeMap) {
this._attributes = attributes;
}
public constructor(id: string) {
this.id = id;
this.attributes = {};
}
}
export class Node extends GraphElement {
public constructor(id: string) {
super(id);
}
}
export class Edge extends GraphElement {
private _source: string;
private _target: string;
public get source(): string {
return this._source
}
public set source(source: string) {
this._source = source;
}
public get target(): string {
return this._target;
}
public set target(target: string) {
this._target = target;
}
public constructor(id: string, source: string, target: string) {
super(id);
this.source = source;
this.target = target;
}
}
export class Graph {
nodes: Array;
edges: Array;
constructor() {
this.nodes = new Array();
this.edges = new Array();
}
}
class AttributeKey {
public name: string;
public dataType: string;
constructor(name: string, dataType: string) {
this.name = name;
this.dataType = dataType;
}
}
interface AttributeKeyMap {
[key: string]: AttributeKey;
}
export class GraphMLParser {
private keys: AttributeKeyMap;
private graph: Graph;
public constructor() {
this.keys = {};
this.graph = new Graph();
}
public parse(text: string, cb?: Function) {
let parser = new Parser();
parser.parseString(text, (err: any, data: any) => {
this.buildKeys(data);
this.buildNodes(data);
this.buildEdges(data);
cb(err, this.graph);
});
}
private buildKeys(data: any) {
for (let i in data.graphml.key) {
const key: any = data.graphml.key[i]['$'];
const keyId: string = key.id;
const name: string = key['attr.name'];
const dataType: string = key['attr.type'];
const newKey: AttributeKey = new AttributeKey(name, dataType);
this.keys[keyId] = newKey;
}
}
private buildNodes(data: any) {
const nodes: any = data.graphml.graph[0].node;
for (let node of nodes) {
const id = node['$'].id;
let newNode: Node = new Node(id);
if (node.data !== undefined) {
this.buildAttributes(newNode.attributes, node.data);
}
this.graph.nodes.push(newNode);
}
}
private buildEdges(data: any) {
const edges: any = data.graphml.graph[0].edge;
for (let edge of edges) {
const id: string = edge['$'].id;
const source: string = edge['$'].source;
const target: string = edge['$'].target;
let newEdge: Edge = new Edge(id, source, target);
if (edge.data !== undefined) {
this.buildAttributes(newEdge.attributes, edge.data);
}
this.graph.edges.push(newEdge);
}
}
private buildAttributes(newAttr: AttributeMap, attributes: any) {
for (let attribute of attributes) {
const attributeKey: string = attribute['$'].key;
const attributeName: string = this.keys[attributeKey].name;
const attributeValue: string = attribute['_'];
const attributeDataType: string = this.keys[attributeKey].dataType;
if (attributeDataType === 'int' ||
attributeDataType === 'long' ||
attributeDataType === 'float' ||
attributeDataType === 'double') {
newAttr[attributeName] = Number(attributeValue);
}
else {
newAttr[attributeName] = attributeValue;
}
}
}
}