From 04a3d5c1caad0b85c8672a1e9a0ee7e54fbe337a Mon Sep 17 00:00:00 2001 From: David Gleich Date: Wed, 30 Oct 2024 21:06:16 -0400 Subject: [PATCH 1/2] Fix circular dependencies --- Project.toml | 9 +- ext/GraphIOParserCombinator.jl | 182 ++++++++++++++++++++++++++++++ ext/GraphIOXML.jl | 195 +++++++++++++++++++++++++++++++++ test/runtests.jl | 7 +- 4 files changed, 384 insertions(+), 9 deletions(-) create mode 100644 ext/GraphIOParserCombinator.jl create mode 100644 ext/GraphIOXML.jl diff --git a/Project.toml b/Project.toml index 918fc3d..710ab5f 100644 --- a/Project.toml +++ b/Project.toml @@ -14,20 +14,21 @@ EzXML = "8f5d6c58-4d21-5cfd-889c-e3ad7ee6a615" ParserCombinator = "fae87a5f-d1ad-5cf0-8f61-c941e1580b46" [extensions] -GraphIODOTExt = "ParserCombinator" -GraphIOGEXFExt = "EzXML" -GraphIOGMLExt = "ParserCombinator" -GraphIOGraphMLExt = "EzXML" +GraphIOParserCombinator = "ParserCombinator" +GraphIOXML = "EzXML" GraphIOLGCompressedExt = "CodecZlib" [compat] +Aqua = "0.8" CodecZlib = "0.7" DelimitedFiles = "1" EzXML = "1" Graphs = "1.4" +JuliaFormatter = "1.0" ParserCombinator = "2.1" Requires = "1" SimpleTraits = "0.9" +Test = "1" julia = "1" [extras] diff --git a/ext/GraphIOParserCombinator.jl b/ext/GraphIOParserCombinator.jl new file mode 100644 index 0000000..d53f5e0 --- /dev/null +++ b/ext/GraphIOParserCombinator.jl @@ -0,0 +1,182 @@ +module GraphIOParserCombinator + +using Graphs +import Graphs: loadgraph, loadgraphs, savegraph + +@static if isdefined(Base, :get_extension) + using GraphIO + using ParserCombinator + import GraphIO.DOT.DOTFormat + import GraphIO.GML.GMLFormat +else # not required for julia >= v1.9 + using ..GraphIO + using ..ParserCombinator + import ..GraphIO.DOT.DOTFormat + import ..GraphIO.GML.GMLFormat +end + +function savedot(io::IO, g::AbstractGraph, gname::String="") + isdir = is_directed(g) + println(io, (isdir ? "digraph " : "graph ") * gname * " {") + for i in vertices(g) + println(io, "\t" * string(i)) + end + if isdir + for u in vertices(g) + out_nbrs = outneighbors(g, u) + length(out_nbrs) == 0 && continue + println(io, "\t" * string(u) * " -> {" * join(out_nbrs, ',') * "}") + end + else + for e in edges(g) + source = string(src(e)) + dest = string(dst(e)) + println(io, "\t" * source * " -- " * dest) + end + end + println(io, "}") + return 1 +end + +function savedot_mult(io::IO, graphs::Dict) + ng = 0 + for (gname, g) in graphs + ng += savedot(io, g, gname) + end + return ng +end + +function _dot_read_one_graph(pg::Parsers.DOT.Graph) + isdir = pg.directed + nvg = length(Parsers.DOT.nodes(pg)) + nodedict = Dict(zip(collect(Parsers.DOT.nodes(pg)), 1:nvg)) + if isdir + g = DiGraph(nvg) + else + g = Graph(nvg) + end + for es in Parsers.DOT.edges(pg) + s = nodedict[es[1]] + d = nodedict[es[2]] + add_edge!(g, s, d) + end + return g +end + +function _name(pg::Parsers.DOT.Graph) + return if pg.id !== nothing + pg.id.id + else + Parsers.DOT.StringID(pg.directed ? "digraph" : "graph") + end +end + +function loaddot(io::IO, gname::String) + p = Parsers.DOT.parse_dot(read(io, String)) + for pg in p + _name(pg) == gname && return _dot_read_one_graph(pg) + end + return error("Graph $gname not found") +end + +function loaddot_mult(io::IO) + p = Parsers.DOT.parse_dot(read(io, String)) + graphs = Dict{String,AbstractGraph}() + + for pg in p + graphs[_name(pg)] = _dot_read_one_graph(pg) + end + return graphs +end + +loadgraph(io::IO, gname::String, ::DOTFormat) = loaddot(io, gname) +loadgraphs(io::IO, ::DOTFormat) = loaddot_mult(io) +savegraph(io::IO, g::AbstractGraph, gname::String, ::DOTFormat) = savedot(io, g, gname) +savegraph(io::IO, d::Dict, ::DOTFormat) = savedot_mult(io, d) + +function _gml_read_one_graph(gs, dir) + nodes = [x[:id] for x in gs[:node]] + if dir + g = DiGraph(length(nodes)) + else + g = Graph(length(nodes)) + end + mapping = Dict{Int,Int}() + for (i, n) in enumerate(nodes) + mapping[n] = i + end + sds = [(Int(x[:source]), Int(x[:target])) for x in gs[:edge]] + for (s, d) in (sds) + add_edge!(g, mapping[s], mapping[d]) + end + return g +end + +function loadgml(io::IO, gname::String) + p = Parsers.GML.parse_dict(read(io, String)) + for gs in p[:graph] + dir = Bool(get(gs, :directed, 0)) + graphname = get(gs, :label, dir ? "digraph" : "graph") + + (gname == graphname) && return _gml_read_one_graph(gs, dir) + end + return error("Graph $gname not found") +end + +function loadgml_mult(io::IO) + p = Parsers.GML.parse_dict(read(io, String)) + graphs = Dict{String,AbstractGraph}() + for gs in p[:graph] + dir = Bool(get(gs, :directed, 0)) + graphname = get(gs, :label, dir ? "digraph" : "graph") + graphs[graphname] = _gml_read_one_graph(gs, dir) + end + return graphs +end + +""" + savegml(f, g, gname="graph") + +Write a graph `g` with name `gname` to an IO stream `io` in the +[GML](https://en.wikipedia.org/wiki/Graph_Modelling_Language) format. Return 1. +""" +function savegml(io::IO, g::AbstractGraph, gname::String="") + println(io, "graph") + println(io, "[") + length(gname) > 0 && println(io, "label \"$gname\"") + is_directed(g) && println(io, "directed 1") + for i in 1:nv(g) + println(io, "\tnode") + println(io, "\t[") + println(io, "\t\tid $i") + println(io, "\t]") + end + for e in edges(g) + s, t = Tuple(e) + println(io, "\tedge") + println(io, "\t[") + println(io, "\t\tsource $s") + println(io, "\t\ttarget $t") + println(io, "\t]") + end + println(io, "]") + return 1 +end + +""" + savegml_mult(io, graphs) +Write a dictionary of (name=>graph) to an IO stream `io` Return number of graphs written. +""" +function savegml_mult(io::IO, graphs::Dict) + ng = 0 + for (gname, g) in graphs + ng += savegml(io, g, gname) + end + return ng +end +loadgraph(io::IO, gname::String, ::GMLFormat) = loadgml(io, gname) +loadgraphs(io::IO, ::GMLFormat) = loadgml_mult(io) +savegraph(io::IO, g::AbstractGraph, gname::String, ::GMLFormat) = savegml(io, g, gname) +savegraph(io::IO, d::Dict, ::GMLFormat) = savegml_mult(io, d) + +end diff --git a/ext/GraphIOXML.jl b/ext/GraphIOXML.jl new file mode 100644 index 0000000..f1e1803 --- /dev/null +++ b/ext/GraphIOXML.jl @@ -0,0 +1,195 @@ +module GraphIOXML + +using Graphs +import Graphs: loadgraph, loadgraphs, savegraph, AbstractGraph + +@static if isdefined(Base, :get_extension) + using GraphIO + using EzXML + import GraphIO.GEXF.GEXFFormat + import GraphIO.GraphML.GraphMLFormat +else # not required for julia >= v1.9 + using ..GraphIO + using ..EzXML + import ..GraphIO.GEXF.GEXFFormat + import ..GraphIO.GraphML.GraphMLFormat +end + +""" + savegexf(f, g, gname) + +Write a graph `g` with name `gname` to an IO stream `io` in the +[Gexf](http://gexf.net/format/) format. Return 1 (number of graphs written). +""" +function savegexf(io::IO, g::AbstractGraph, gname::String) + xdoc = XMLDocument() + xroot = setroot!(xdoc, ElementNode("gexf")) + xroot["xmlns"] = "http://www.gexf.net/1.2draft" + xroot["version"] = "1.2" + xroot["xmlns:xsi"] = "http://www.w3.org/2001/XMLSchema-instance" + xroot["xsi:schemaLocation"] = "http://www.gexf.net/1.2draft/gexf.xsd" + + xmeta = addelement!(xroot, "meta") + addelement!(xmeta, "description", gname) + xg = addelement!(xroot, "graph") + strdir = is_directed(g) ? "directed" : "undirected" + xg["defaultedgetype"] = strdir + + xnodes = addelement!(xg, "nodes") + for i in 1:nv(g) + xv = addelement!(xnodes, "node") + xv["id"] = "$(i-1)" + end + + xedges = addelement!(xg, "edges") + m = 0 + for e in edges(g) + xe = addelement!(xedges, "edge") + xe["id"] = "$m" + xe["source"] = "$(src(e)-1)" + xe["target"] = "$(dst(e)-1)" + m += 1 + end + + prettyprint(io, xdoc) + return 1 +end + +savegraph(io::IO, g::AbstractGraph, gname::String, ::GEXFFormat) = savegexf(io, g, gname) + +function _graphml_read_one_graph(reader::EzXML.StreamReader, isdirected::Bool) + nodes = Dict{String,Int}() + xedges = Vector{Edge}() + nodeid = 1 + for typ in reader + if typ == EzXML.READER_ELEMENT + elname = EzXML.nodename(reader) + if elname == "node" + nodes[reader["id"]] = nodeid + nodeid += 1 + elseif elname == "edge" + src = reader["source"] + tar = reader["target"] + push!(xedges, Edge(nodes[src], nodes[tar])) + else + @warn "Skipping unknown node '$(elname)' - further warnings will be suppressed" maxlog = + 1 _id = :unknode + end + end + end + g = (isdirected ? DiGraph : Graph)(length(nodes)) + for edge in xedges + add_edge!(g, edge) + end + return g +end + +function loadgraphml(io::IO, gname::String) + reader = EzXML.StreamReader(io) + for typ in reader + if typ == EzXML.READER_ELEMENT + elname = EzXML.nodename(reader) + if elname == "graphml" + # ok + elseif elname == "graph" + edgedefault = reader["edgedefault"] + directed = if edgedefault == "directed" + true + elseif edgedefault == "undirected" + false + else + error("Unknown value of edgedefault: $edgedefault") + end + if haskey(reader, "id") + graphname = reader["id"] + else + graphname = directed ? "digraph" : "graph" + end + if gname == graphname + return _graphml_read_one_graph(reader, directed) + end + elseif elname == "node" || elname == "edge" + # ok + else + @warn "Skipping unknown XML element '$(elname)' - further warnings will be suppressed" maxlog = + 1 _id = :unkel + end + end + end + return error("Graph $gname not found") +end + +function loadgraphml_mult(io::IO) + reader = EzXML.StreamReader(io) + graphs = Dict{String,AbstractGraph}() + for typ in reader + if typ == EzXML.READER_ELEMENT + elname = EzXML.nodename(reader) + if elname == "graphml" + # ok + elseif elname == "graph" + edgedefault = reader["edgedefault"] + directed = if edgedefault == "directed" + true + elseif edgedefault == "undirected" + false + else + error("Unknown value of edgedefault: $edgedefault") + end + if haskey(reader, "id") + graphname = reader["id"] + else + graphname = directed ? "digraph" : "graph" + end + graphs[graphname] = _graphml_read_one_graph(reader, directed) + else + @warn "Skipping unknown XML element '$(elname)' - further warnings will be suppressed" maxlog = + 1 _id = :unkelmult + end + end + end + return graphs +end + +function savegraphml_mult(io::IO, graphs::Dict) + xdoc = XMLDocument() + xroot = setroot!(xdoc, ElementNode("graphml")) + xroot["xmlns"] = "http://graphml.graphdrawing.org/xmlns" + xroot["xmlns:xsi"] = "http://www.w3.org/2001/XMLSchema-instance" + xroot["xsi:schemaLocation"] = "http://graphml.graphdrawing.org/xmlns/1.0/graphml.xsd" + + for (gname, g) in graphs + xg = addelement!(xroot, "graph") + xg["id"] = gname + xg["edgedefault"] = is_directed(g) ? "directed" : "undirected" + + for i in 1:nv(g) + xv = addelement!(xg, "node") + xv["id"] = "n$(i-1)" + end + + m = 0 + for e in edges(g) + xe = addelement!(xg, "edge") + xe["id"] = "e$m" + xe["source"] = "n$(src(e)-1)" + xe["target"] = "n$(dst(e)-1)" + m += 1 + end + end + prettyprint(io, xdoc) + return length(graphs) +end + +function savegraphml(io::IO, g::AbstractGraph, gname::String) + return savegraphml_mult(io, Dict(gname => g)) +end + +loadgraph(io::IO, gname::String, ::GraphMLFormat) = loadgraphml(io, gname) +loadgraphs(io::IO, ::GraphMLFormat) = loadgraphml_mult(io) +function savegraph(io::IO, g::AbstractGraph, gname::String, ::GraphMLFormat) + return savegraphml(io, g, gname) +end +savegraph(io::IO, d::Dict, ::GraphMLFormat) = savegraphml_mult(io, d) + +end diff --git a/test/runtests.jl b/test/runtests.jl index cc08fe4..cde99ce 100644 --- a/test/runtests.jl +++ b/test/runtests.jl @@ -15,14 +15,11 @@ include("graphio.jl") # write your own tests here @testset verbose = true "GraphIO" begin @testset "Code quality" begin - Aqua.test_all(GraphIO; stale_deps=false, project_toml_formatting=false) + Aqua.test_all(GraphIO; stale_deps=false) Aqua.test_stale_deps(GraphIO; ignore=[:Requires]) - if VERSION >= v"1.9" - Aqua.test_project_toml_formatting(GraphIO) - end end @testset "Code formatting" begin - @test JuliaFormatter.format(GraphIO; verbose=false, overwrite=false) + @test JuliaFormatter.format(GraphIO; verbose=true, overwrite=false) end for name in modules path = joinpath(testdir, name, "runtests.jl") From 75163e8d975c3977d9e3b1f9331e1218886b5fb1 Mon Sep 17 00:00:00 2001 From: Guillaume Dalle <22795598+gdalle@users.noreply.github.com> Date: Wed, 6 Nov 2024 11:05:39 +0100 Subject: [PATCH 2/2] Remove old extension files --- ext/GraphIODOTExt.jl | 95 --------------------- ext/GraphIOGEXFExt.jl | 58 ------------- ext/GraphIOGMLExt.jl | 101 ---------------------- ext/GraphIOGraphMLExt.jl | 151 --------------------------------- ext/GraphIOLGCompressedExt.jl | 12 +-- ext/GraphIOParserCombinator.jl | 15 +--- ext/GraphIOXML.jl | 15 +--- 7 files changed, 11 insertions(+), 436 deletions(-) delete mode 100644 ext/GraphIODOTExt.jl delete mode 100644 ext/GraphIOGEXFExt.jl delete mode 100644 ext/GraphIOGMLExt.jl delete mode 100644 ext/GraphIOGraphMLExt.jl diff --git a/ext/GraphIODOTExt.jl b/ext/GraphIODOTExt.jl deleted file mode 100644 index f424e9d..0000000 --- a/ext/GraphIODOTExt.jl +++ /dev/null @@ -1,95 +0,0 @@ -module GraphIODOTExt - -using Graphs -import Graphs: loadgraph, loadgraphs, savegraph - -@static if isdefined(Base, :get_extension) - using GraphIO - using ParserCombinator - import GraphIO.DOT.DOTFormat -else # not required for julia >= v1.9 - using ..GraphIO - using ..ParserCombinator - import ..GraphIO.DOT.DOTFormat -end - -function savedot(io::IO, g::AbstractGraph, gname::String="") - isdir = is_directed(g) - println(io, (isdir ? "digraph " : "graph ") * gname * " {") - for i in vertices(g) - println(io, "\t" * string(i)) - end - if isdir - for u in vertices(g) - out_nbrs = outneighbors(g, u) - length(out_nbrs) == 0 && continue - println(io, "\t" * string(u) * " -> {" * join(out_nbrs, ',') * "}") - end - else - for e in edges(g) - source = string(src(e)) - dest = string(dst(e)) - println(io, "\t" * source * " -- " * dest) - end - end - println(io, "}") - return 1 -end - -function savedot_mult(io::IO, graphs::Dict) - ng = 0 - for (gname, g) in graphs - ng += savedot(io, g, gname) - end - return ng -end - -function _dot_read_one_graph(pg::Parsers.DOT.Graph) - isdir = pg.directed - nvg = length(Parsers.DOT.nodes(pg)) - nodedict = Dict(zip(collect(Parsers.DOT.nodes(pg)), 1:nvg)) - if isdir - g = DiGraph(nvg) - else - g = Graph(nvg) - end - for es in Parsers.DOT.edges(pg) - s = nodedict[es[1]] - d = nodedict[es[2]] - add_edge!(g, s, d) - end - return g -end - -function _name(pg::Parsers.DOT.Graph) - return if pg.id !== nothing - pg.id.id - else - Parsers.DOT.StringID(pg.directed ? "digraph" : "graph") - end -end - -function loaddot(io::IO, gname::String) - p = Parsers.DOT.parse_dot(read(io, String)) - for pg in p - _name(pg) == gname && return _dot_read_one_graph(pg) - end - return error("Graph $gname not found") -end - -function loaddot_mult(io::IO) - p = Parsers.DOT.parse_dot(read(io, String)) - graphs = Dict{String,AbstractGraph}() - - for pg in p - graphs[_name(pg)] = _dot_read_one_graph(pg) - end - return graphs -end - -loadgraph(io::IO, gname::String, ::DOTFormat) = loaddot(io, gname) -loadgraphs(io::IO, ::DOTFormat) = loaddot_mult(io) -savegraph(io::IO, g::AbstractGraph, gname::String, ::DOTFormat) = savedot(io, g, gname) -savegraph(io::IO, d::Dict, ::DOTFormat) = savedot_mult(io, d) - -end diff --git a/ext/GraphIOGEXFExt.jl b/ext/GraphIOGEXFExt.jl deleted file mode 100644 index fe2cbf6..0000000 --- a/ext/GraphIOGEXFExt.jl +++ /dev/null @@ -1,58 +0,0 @@ -module GraphIOGEXFExt - -using Graphs -import Graphs: loadgraph, loadgraphs, savegraph, AbstractGraph - -@static if isdefined(Base, :get_extension) - using GraphIO - using EzXML - import GraphIO.GEXF.GEXFFormat -else # not required for julia >= v1.9 - using ..GraphIO - using ..EzXML - import ..GraphIO.GEXF.GEXFFormat -end - -""" - savegexf(f, g, gname) - -Write a graph `g` with name `gname` to an IO stream `io` in the -[Gexf](http://gexf.net/format/) format. Return 1 (number of graphs written). -""" -function savegexf(io::IO, g::AbstractGraph, gname::String) - xdoc = XMLDocument() - xroot = setroot!(xdoc, ElementNode("gexf")) - xroot["xmlns"] = "http://www.gexf.net/1.2draft" - xroot["version"] = "1.2" - xroot["xmlns:xsi"] = "http://www.w3.org/2001/XMLSchema-instance" - xroot["xsi:schemaLocation"] = "http://www.gexf.net/1.2draft/gexf.xsd" - - xmeta = addelement!(xroot, "meta") - addelement!(xmeta, "description", gname) - xg = addelement!(xroot, "graph") - strdir = is_directed(g) ? "directed" : "undirected" - xg["defaultedgetype"] = strdir - - xnodes = addelement!(xg, "nodes") - for i in 1:nv(g) - xv = addelement!(xnodes, "node") - xv["id"] = "$(i-1)" - end - - xedges = addelement!(xg, "edges") - m = 0 - for e in edges(g) - xe = addelement!(xedges, "edge") - xe["id"] = "$m" - xe["source"] = "$(src(e)-1)" - xe["target"] = "$(dst(e)-1)" - m += 1 - end - - prettyprint(io, xdoc) - return 1 -end - -savegraph(io::IO, g::AbstractGraph, gname::String, ::GEXFFormat) = savegexf(io, g, gname) - -end diff --git a/ext/GraphIOGMLExt.jl b/ext/GraphIOGMLExt.jl deleted file mode 100644 index 951d498..0000000 --- a/ext/GraphIOGMLExt.jl +++ /dev/null @@ -1,101 +0,0 @@ -module GraphIOGMLExt - -using Graphs -import Graphs: loadgraph, loadgraphs, savegraph - -@static if isdefined(Base, :get_extension) - using GraphIO - using ParserCombinator - import GraphIO.GML.GMLFormat -else # not required for julia >= v1.9 - using ..GraphIO - using ..ParserCombinator - import ..GraphIO.GML.GMLFormat -end - -function _gml_read_one_graph(gs, dir) - nodes = [x[:id] for x in gs[:node]] - if dir - g = DiGraph(length(nodes)) - else - g = Graph(length(nodes)) - end - mapping = Dict{Int,Int}() - for (i, n) in enumerate(nodes) - mapping[n] = i - end - sds = [(Int(x[:source]), Int(x[:target])) for x in gs[:edge]] - for (s, d) in (sds) - add_edge!(g, mapping[s], mapping[d]) - end - return g -end - -function loadgml(io::IO, gname::String) - p = Parsers.GML.parse_dict(read(io, String)) - for gs in p[:graph] - dir = Bool(get(gs, :directed, 0)) - graphname = get(gs, :label, dir ? "digraph" : "graph") - - (gname == graphname) && return _gml_read_one_graph(gs, dir) - end - return error("Graph $gname not found") -end - -function loadgml_mult(io::IO) - p = Parsers.GML.parse_dict(read(io, String)) - graphs = Dict{String,AbstractGraph}() - for gs in p[:graph] - dir = Bool(get(gs, :directed, 0)) - graphname = get(gs, :label, dir ? "digraph" : "graph") - graphs[graphname] = _gml_read_one_graph(gs, dir) - end - return graphs -end - -""" - savegml(f, g, gname="graph") - -Write a graph `g` with name `gname` to an IO stream `io` in the -[GML](https://en.wikipedia.org/wiki/Graph_Modelling_Language) format. Return 1. -""" -function savegml(io::IO, g::AbstractGraph, gname::String="") - println(io, "graph") - println(io, "[") - length(gname) > 0 && println(io, "label \"$gname\"") - is_directed(g) && println(io, "directed 1") - for i in 1:nv(g) - println(io, "\tnode") - println(io, "\t[") - println(io, "\t\tid $i") - println(io, "\t]") - end - for e in edges(g) - s, t = Tuple(e) - println(io, "\tedge") - println(io, "\t[") - println(io, "\t\tsource $s") - println(io, "\t\ttarget $t") - println(io, "\t]") - end - println(io, "]") - return 1 -end - -""" - savegml_mult(io, graphs) -Write a dictionary of (name=>graph) to an IO stream `io` Return number of graphs written. -""" -function savegml_mult(io::IO, graphs::Dict) - ng = 0 - for (gname, g) in graphs - ng += savegml(io, g, gname) - end - return ng -end -loadgraph(io::IO, gname::String, ::GMLFormat) = loadgml(io, gname) -loadgraphs(io::IO, ::GMLFormat) = loadgml_mult(io) -savegraph(io::IO, g::AbstractGraph, gname::String, ::GMLFormat) = savegml(io, g, gname) -savegraph(io::IO, d::Dict, ::GMLFormat) = savegml_mult(io, d) - -end diff --git a/ext/GraphIOGraphMLExt.jl b/ext/GraphIOGraphMLExt.jl deleted file mode 100644 index 99e28b1..0000000 --- a/ext/GraphIOGraphMLExt.jl +++ /dev/null @@ -1,151 +0,0 @@ -module GraphIOGraphMLExt - -using Graphs -import Graphs: loadgraph, loadgraphs, savegraph - -@static if isdefined(Base, :get_extension) - using GraphIO - using EzXML - import GraphIO.GraphML.GraphMLFormat -else # not required for julia >= v1.9 - using ..GraphIO - using ..EzXML - import ..GraphIO.GraphML.GraphMLFormat -end - -function _graphml_read_one_graph(reader::EzXML.StreamReader, isdirected::Bool) - nodes = Dict{String,Int}() - xedges = Vector{Edge}() - nodeid = 1 - for typ in reader - if typ == EzXML.READER_ELEMENT - elname = EzXML.nodename(reader) - if elname == "node" - nodes[reader["id"]] = nodeid - nodeid += 1 - elseif elname == "edge" - src = reader["source"] - tar = reader["target"] - push!(xedges, Edge(nodes[src], nodes[tar])) - else - @warn "Skipping unknown node '$(elname)' - further warnings will be suppressed" maxlog = - 1 _id = :unknode - end - end - end - g = (isdirected ? DiGraph : Graph)(length(nodes)) - for edge in xedges - add_edge!(g, edge) - end - return g -end - -function loadgraphml(io::IO, gname::String) - reader = EzXML.StreamReader(io) - for typ in reader - if typ == EzXML.READER_ELEMENT - elname = EzXML.nodename(reader) - if elname == "graphml" - # ok - elseif elname == "graph" - edgedefault = reader["edgedefault"] - directed = if edgedefault == "directed" - true - elseif edgedefault == "undirected" - false - else - error("Unknown value of edgedefault: $edgedefault") - end - if haskey(reader, "id") - graphname = reader["id"] - else - graphname = directed ? "digraph" : "graph" - end - if gname == graphname - return _graphml_read_one_graph(reader, directed) - end - elseif elname == "node" || elname == "edge" - # ok - else - @warn "Skipping unknown XML element '$(elname)' - further warnings will be suppressed" maxlog = - 1 _id = :unkel - end - end - end - return error("Graph $gname not found") -end - -function loadgraphml_mult(io::IO) - reader = EzXML.StreamReader(io) - graphs = Dict{String,AbstractGraph}() - for typ in reader - if typ == EzXML.READER_ELEMENT - elname = EzXML.nodename(reader) - if elname == "graphml" - # ok - elseif elname == "graph" - edgedefault = reader["edgedefault"] - directed = if edgedefault == "directed" - true - elseif edgedefault == "undirected" - false - else - error("Unknown value of edgedefault: $edgedefault") - end - if haskey(reader, "id") - graphname = reader["id"] - else - graphname = directed ? "digraph" : "graph" - end - graphs[graphname] = _graphml_read_one_graph(reader, directed) - else - @warn "Skipping unknown XML element '$(elname)' - further warnings will be suppressed" maxlog = - 1 _id = :unkelmult - end - end - end - return graphs -end - -function savegraphml_mult(io::IO, graphs::Dict) - xdoc = XMLDocument() - xroot = setroot!(xdoc, ElementNode("graphml")) - xroot["xmlns"] = "http://graphml.graphdrawing.org/xmlns" - xroot["xmlns:xsi"] = "http://www.w3.org/2001/XMLSchema-instance" - xroot["xsi:schemaLocation"] = "http://graphml.graphdrawing.org/xmlns/1.0/graphml.xsd" - - for (gname, g) in graphs - xg = addelement!(xroot, "graph") - xg["id"] = gname - xg["edgedefault"] = is_directed(g) ? "directed" : "undirected" - - for i in 1:nv(g) - xv = addelement!(xg, "node") - xv["id"] = "n$(i-1)" - end - - m = 0 - for e in edges(g) - xe = addelement!(xg, "edge") - xe["id"] = "e$m" - xe["source"] = "n$(src(e)-1)" - xe["target"] = "n$(dst(e)-1)" - m += 1 - end - end - prettyprint(io, xdoc) - return length(graphs) -end - -function savegraphml(io::IO, g::AbstractGraph, gname::String) - return savegraphml_mult(io, Dict(gname => g)) -end - -loadgraph(io::IO, gname::String, ::GraphMLFormat) = loadgraphml(io, gname) -loadgraphs(io::IO, ::GraphMLFormat) = loadgraphml_mult(io) -function savegraph(io::IO, g::AbstractGraph, gname::String, ::GraphMLFormat) - return savegraphml(io, g, gname) -end -savegraph(io::IO, d::Dict, ::GraphMLFormat) = savegraphml_mult(io, d) - -end diff --git a/ext/GraphIOLGCompressedExt.jl b/ext/GraphIOLGCompressedExt.jl index 96a2c72..4f812d8 100644 --- a/ext/GraphIOLGCompressedExt.jl +++ b/ext/GraphIOLGCompressedExt.jl @@ -3,15 +3,9 @@ module GraphIOLGCompressedExt using Graphs import Graphs: loadgraph, loadgraphs, savegraph, LGFormat -@static if isdefined(Base, :get_extension) - using GraphIO - using CodecZlib - import GraphIO.LGCompressed.LGCompressedFormat -else # not required for julia >= v1.9 - using ..GraphIO - using ..CodecZlib - import ..GraphIO.LGCompressed.LGCompressedFormat -end +using GraphIO +using CodecZlib +import GraphIO.LGCompressed.LGCompressedFormat function savegraph( fn::AbstractString, g::AbstractGraph, gname::AbstractString, format::LGCompressedFormat diff --git a/ext/GraphIOParserCombinator.jl b/ext/GraphIOParserCombinator.jl index d53f5e0..1bb641d 100644 --- a/ext/GraphIOParserCombinator.jl +++ b/ext/GraphIOParserCombinator.jl @@ -3,17 +3,10 @@ module GraphIOParserCombinator using Graphs import Graphs: loadgraph, loadgraphs, savegraph -@static if isdefined(Base, :get_extension) - using GraphIO - using ParserCombinator - import GraphIO.DOT.DOTFormat - import GraphIO.GML.GMLFormat -else # not required for julia >= v1.9 - using ..GraphIO - using ..ParserCombinator - import ..GraphIO.DOT.DOTFormat - import ..GraphIO.GML.GMLFormat -end +using GraphIO +using ParserCombinator +import GraphIO.DOT.DOTFormat +import GraphIO.GML.GMLFormat function savedot(io::IO, g::AbstractGraph, gname::String="") isdir = is_directed(g) diff --git a/ext/GraphIOXML.jl b/ext/GraphIOXML.jl index f1e1803..4a22fab 100644 --- a/ext/GraphIOXML.jl +++ b/ext/GraphIOXML.jl @@ -3,17 +3,10 @@ module GraphIOXML using Graphs import Graphs: loadgraph, loadgraphs, savegraph, AbstractGraph -@static if isdefined(Base, :get_extension) - using GraphIO - using EzXML - import GraphIO.GEXF.GEXFFormat - import GraphIO.GraphML.GraphMLFormat -else # not required for julia >= v1.9 - using ..GraphIO - using ..EzXML - import ..GraphIO.GEXF.GEXFFormat - import ..GraphIO.GraphML.GraphMLFormat -end +using GraphIO +using EzXML +import GraphIO.GEXF.GEXFFormat +import GraphIO.GraphML.GraphMLFormat """ savegexf(f, g, gname)