Skip to content

Commit 6cbba33

Browse files
committed
Initial commit
0 parents  commit 6cbba33

10 files changed

Lines changed: 477 additions & 0 deletions

File tree

.gitignore

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,2 @@
1+
/vendor
2+
/composer.lock

.travis.yml

Lines changed: 11 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,11 @@
1+
language: php
2+
php:
3+
- 5.6
4+
- 5.5
5+
- 5.4
6+
- 5.3
7+
- hhvm
8+
before_script:
9+
- composer install --prefer-source --no-interaction
10+
script:
11+
- php vendor/bin/phpunit --coverage-text

CHANGELOG.md

Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,9 @@
1+
# CHANGELOG
2+
3+
This file is a manually maintained list of changes for each release. Feel free
4+
to add your changes here when sending pull requests. Also send corrections if
5+
you spot any mistakes.
6+
7+
## 0.1.0 (2015-xx-xx)
8+
9+
* First tagged release

LICENSE

Lines changed: 21 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,21 @@
1+
The MIT License (MIT)
2+
3+
Copyright (c) 2015 Christian Lück
4+
5+
Permission is hereby granted, free of charge, to any person obtaining a copy
6+
of this software and associated documentation files (the "Software"), to deal
7+
in the Software without restriction, including without limitation the rights
8+
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
9+
copies of the Software, and to permit persons to whom the Software is furnished
10+
to do so, subject to the following conditions:
11+
12+
The above copyright notice and this permission notice shall be included in all
13+
copies or substantial portions of the Software.
14+
15+
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16+
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17+
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
18+
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19+
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
20+
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
21+
THE SOFTWARE.

README.md

Lines changed: 21 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,21 @@
1+
# graphp/graphml [![Build Status](https://travis-ci.org/graphp/graphml.svg?branch=master)](https://travis-ci.org/graphp/graphml)
2+
3+
[GraphML](http://graphml.graphdrawing.org/) is an XML-based file format for graphs
4+
5+
> Note: This project is in early alpha stage! Feel free to report any issues you encounter.
6+
7+
## Install
8+
9+
The recommended way to install this library is [through composer](http://getcomposer.org). [New to composer?](http://getcomposer.org/doc/00-intro.md)
10+
11+
```JSON
12+
{
13+
"require": {
14+
"graphp/graphml": "dev-master"
15+
}
16+
}
17+
```
18+
19+
## License
20+
21+
Released under the terms of the permissive [MIT license](http://opensource.org/licenses/MIT).

composer.json

Lines changed: 24 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,24 @@
1+
{
2+
"name": "graphp/graphml",
3+
"description": "GraphML is an XML-based file format for graphs",
4+
"keywords": ["GraphML", "Graph XML"],
5+
"homepage": "https://github.com/graphp/graphml",
6+
"license": "MIT",
7+
"authors": [
8+
{
9+
"name": "Christian Lück",
10+
"email": "christian@lueck.tv"
11+
}
12+
],
13+
"require": {
14+
"php": ">=5.3",
15+
"ext-simplexml": "*",
16+
"clue/graph": "~0.8.0"
17+
},
18+
"require-dev": {
19+
"phpunit/phpunit": "~4.0"
20+
},
21+
"autoload": {
22+
"psr-4": {"Graphp\\GraphML\\": "src/"}
23+
}
24+
}

phpunit.xml.dist

Lines changed: 19 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,19 @@
1+
<?xml version="1.0" encoding="UTF-8"?>
2+
3+
<phpunit bootstrap="tests/bootstrap.php"
4+
colors="true"
5+
convertErrorsToExceptions="true"
6+
convertNoticesToExceptions="true"
7+
convertWarningsToExceptions="true"
8+
>
9+
<testsuites>
10+
<testsuite name="GraphML Test Suite">
11+
<directory>./tests/</directory>
12+
</testsuite>
13+
</testsuites>
14+
<filter>
15+
<whitelist>
16+
<directory>./src</directory>
17+
</whitelist>
18+
</filter>
19+
</phpunit>

src/Loader.php

Lines changed: 92 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,92 @@
1+
<?php
2+
3+
namespace Graphp\GraphML;
4+
5+
use SimpleXMLElement;
6+
use Fhaculty\Graph\Graph;
7+
use Fhaculty\Graph\Attribute\AttributeAware;
8+
9+
class Loader
10+
{
11+
public function loadContents($contents)
12+
{
13+
return $this->loadXml(new SimpleXMLElement($contents));
14+
}
15+
16+
private function loadXml(SimpleXMLElement $root)
17+
{
18+
$graph = new Graph();
19+
20+
// parse all attribute keys
21+
$keys = array();
22+
foreach ($root->key as $keyElem) {
23+
$keys[(string)$keyElem['id']] = array(
24+
'name' => (string)$keyElem['attr.name'],
25+
'type' => (string)$keyElem['attr.type'],
26+
'for' => (isset($keyElem['for']) ? (string)$keyElem['for'] : 'all'),
27+
'default' => (isset($keyElem->default) ? $this->castAttribute((string)$keyElem->default, (string)$keyElem['attr.type']) : null)
28+
);
29+
}
30+
31+
// load global graph settings
32+
$edgedefault = ((string)$root->graph['edgedefault'] === 'directed');
33+
$this->loadAttributes($root->graph, $graph, $keys);
34+
35+
// load all vertices (known as "nodes" in GraphML)
36+
foreach ($root->graph->node as $nodeElem) {
37+
$vertex = $graph->createVertex((string)$nodeElem['id']);
38+
39+
$this->loadAttributes($nodeElem, $vertex, $keys);
40+
}
41+
42+
// load all edges
43+
foreach ($root->graph->edge as $edgeElem) {
44+
$source = $graph->getVertex((string)$edgeElem['source']);
45+
$target = $graph->getVertex((string)$edgeElem['target']);
46+
47+
$directed = $edgedefault;
48+
if (isset($edgeElem['directed'])) {
49+
$directed = ((string)$edgeElem['directed'] === 'true');
50+
}
51+
52+
if ($directed) {
53+
$edge = $source->createEdgeTo($target);
54+
} else {
55+
$edge = $source->createEdge($target);
56+
}
57+
58+
$this->loadAttributes($edgeElem, $edge, $keys);
59+
}
60+
61+
return $graph;
62+
}
63+
64+
private function loadAttributes(SimpleXMLElement $xml, AttributeAware $target, array $keys)
65+
{
66+
// apply all default values for this type
67+
$type = $xml->getName();
68+
foreach ($keys as $key) {
69+
if (isset($key['default']) && ($key['for'] === $type || $key['for'] === 'all')) {
70+
$target->setAttribute($key['name'], $key['default']);
71+
}
72+
}
73+
74+
// apply all data attributes for this element
75+
foreach ($xml->data as $dataElem) {
76+
$key = $keys[(string)$dataElem['key']];
77+
$target->setAttribute($key['name'], $this->castAttribute((string)$dataElem, $key['type']));
78+
}
79+
}
80+
81+
private function castAttribute($value, $type)
82+
{
83+
if ($type === 'boolean') {
84+
return ($value === 'true');
85+
} elseif ($type === 'int' || $type === 'long') {
86+
return (int)$value;
87+
} elseif ($type === 'float' || $type === 'double') {
88+
return (float)$value;
89+
}
90+
return $value;
91+
}
92+
}

tests/LoaderTest.php

Lines changed: 178 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,178 @@
1+
<?php
2+
3+
use Graphp\GraphML\Loader;
4+
5+
class LoaderTest extends TestCase
6+
{
7+
private $loader;
8+
9+
public function setUp()
10+
{
11+
$this->loader = new Loader();
12+
}
13+
14+
public function testEmpty()
15+
{
16+
$data = <<<EOL
17+
<?xml version="1.0" encoding="UTF-8"?>
18+
<graphml xmlns="http://graphml.graphdrawing.org/xmlns"
19+
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
20+
xsi:schemaLocation="http://graphml.graphdrawing.org/xmlns
21+
http://graphml.graphdrawing.org/xmlns/1.0/graphml.xsd">
22+
<graph id="G" edgedefault="undirected">
23+
</graph>
24+
</graphml>
25+
EOL;
26+
27+
$graph = $this->loader->loadContents($data);
28+
29+
$this->assertCount(0, $graph->getVertices());
30+
}
31+
32+
public function testSimpleGraph()
33+
{
34+
$data = <<<EOL
35+
<?xml version="1.0" encoding="UTF-8"?>
36+
<graphml xmlns="http://graphml.graphdrawing.org/xmlns"
37+
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
38+
xsi:schemaLocation="http://graphml.graphdrawing.org/xmlns
39+
http://graphml.graphdrawing.org/xmlns/1.0/graphml.xsd">
40+
<graph id="G" edgedefault="undirected">
41+
<node id="n0"/>
42+
<node id="n1"/>
43+
<node id="n2"/>
44+
<node id="n3"/>
45+
<node id="n4"/>
46+
<node id="n5"/>
47+
<node id="n6"/>
48+
<node id="n7"/>
49+
<node id="n8"/>
50+
<node id="n9"/>
51+
<node id="n10"/>
52+
<edge source="n0" target="n2"/>
53+
<edge source="n1" target="n2"/>
54+
<edge source="n2" target="n3"/>
55+
<edge source="n3" target="n5"/>
56+
<edge source="n3" target="n4"/>
57+
<edge source="n4" target="n6"/>
58+
<edge source="n6" target="n5"/>
59+
<edge source="n5" target="n7"/>
60+
<edge source="n6" target="n8"/>
61+
<edge source="n8" target="n7"/>
62+
<edge source="n8" target="n9"/>
63+
<edge source="n8" target="n10"/>
64+
</graph>
65+
</graphml>
66+
EOL;
67+
68+
$graph = $this->loader->loadContents($data);
69+
70+
$this->assertCount(11, $graph->getVertices());
71+
$this->assertCount(12, $graph->getEdges());
72+
}
73+
74+
public function testEdgeUndirected()
75+
{
76+
$data = <<<EOL
77+
<?xml version="1.0" encoding="UTF-8"?>
78+
<graphml xmlns="http://graphml.graphdrawing.org/xmlns"
79+
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
80+
xsi:schemaLocation="http://graphml.graphdrawing.org/xmlns
81+
http://graphml.graphdrawing.org/xmlns/1.0/graphml.xsd">
82+
<graph id="G" edgedefault="undirected">
83+
<node id="n0"/>
84+
<edge source="n0" target="n0" directed="false"/>
85+
<edge source="n0" target="n0"/>
86+
</graph>
87+
</graphml>
88+
EOL;
89+
90+
$graph = $this->loader->loadContents($data);
91+
92+
$this->assertCount(2, $graph->getEdges());
93+
$this->assertInstanceOf('Fhaculty\Graph\Edge\Undirected', $graph->getEdges()->getEdgeFirst());
94+
$this->assertInstanceOf('Fhaculty\Graph\Edge\Undirected', $graph->getEdges()->getEdgeLast());
95+
}
96+
97+
public function testEdgeDirected()
98+
{
99+
$data = <<<EOL
100+
<?xml version="1.0" encoding="UTF-8"?>
101+
<graphml xmlns="http://graphml.graphdrawing.org/xmlns"
102+
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
103+
xsi:schemaLocation="http://graphml.graphdrawing.org/xmlns
104+
http://graphml.graphdrawing.org/xmlns/1.0/graphml.xsd">
105+
<graph id="G" edgedefault="directed">
106+
<node id="n0"/>
107+
<edge source="n0" target="n0" directed="true"/>
108+
<edge source="n0" target="n0"/>
109+
</graph>
110+
</graphml>
111+
EOL;
112+
113+
$graph = $this->loader->loadContents($data);
114+
115+
$this->assertCount(2, $graph->getEdges());
116+
$this->assertInstanceOf('Fhaculty\Graph\Edge\Directed', $graph->getEdges()->getEdgeFirst());
117+
$this->assertInstanceOf('Fhaculty\Graph\Edge\Directed', $graph->getEdges()->getEdgeLast());
118+
}
119+
120+
public function testAttributeTypes()
121+
{
122+
$data = <<<EOL
123+
<?xml version="1.0" encoding="UTF-8"?>
124+
<graphml xmlns="http://graphml.graphdrawing.org/xmlns"
125+
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
126+
xsi:schemaLocation="http://graphml.graphdrawing.org/xmlns
127+
http://graphml.graphdrawing.org/xmlns/1.0/graphml.xsd">
128+
<key id="d0" for="node" attr.name="string" attr.type="string"></key>
129+
<key id="d1" for="node" attr.name="boolean" attr.type="boolean"></key>
130+
<key id="d2" for="node" attr.name="float" attr.type="float"></key>
131+
<key id="d3" for="node" attr.name="int" attr.type="int"></key>
132+
<graph id="G" edgedefault="undirected">
133+
<node id="n0">
134+
<data key="d0">text</data>
135+
<data key="d1">true</data>
136+
<data key="d2">4.5</data>
137+
<data key="d3">3</data>
138+
</node>
139+
</graph>
140+
</graphml>
141+
EOL;
142+
143+
$graph = $this->loader->loadContents($data);
144+
145+
$vertex = $graph->getVertices()->getVertexFirst();
146+
147+
$this->assertEquals('n0', $vertex->getId());
148+
$this->assertSame('text', $vertex->getAttribute('string'));
149+
$this->assertSame(true, $vertex->getAttribute('boolean'));
150+
$this->assertSame(4.5, $vertex->getAttribute('float'));
151+
$this->assertSame(3, $vertex->getAttribute('int'));
152+
}
153+
154+
public function testAttributeDefault()
155+
{
156+
$data = <<<EOL
157+
<?xml version="1.0" encoding="UTF-8"?>
158+
<graphml xmlns="http://graphml.graphdrawing.org/xmlns"
159+
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
160+
xsi:schemaLocation="http://graphml.graphdrawing.org/xmlns
161+
http://graphml.graphdrawing.org/xmlns/1.0/graphml.xsd">
162+
<key id="d0" for="node" attr.name="color" attr.type="string">
163+
<default>yellow</default>
164+
</key>
165+
<graph id="G" edgedefault="undirected">
166+
<node id="n0"/>
167+
</graph>
168+
</graphml>
169+
EOL;
170+
171+
$graph = $this->loader->loadContents($data);
172+
173+
$vertex = $graph->getVertices()->getVertexFirst();
174+
175+
$this->assertEquals('n0', $vertex->getId());
176+
$this->assertEquals('yellow', $vertex->getAttribute('color'));
177+
}
178+
}

0 commit comments

Comments
 (0)