///|
fn write_locator(output : Output, locator : Locator) -> Unit raise GraphError {
let attributes = [
{ namespace_uri: Some(XLINK_URI), name: "href", value: locator.href, },
]
if locator.link_type is Some(value) {
attributes.push({ namespace_uri: Some(XLINK_URI), name: "type", value, })
}
attributes.append(locator.extra)
output.graphml_start("locator", attributes, namespaces=locator.namespaces)
output.end("locator")
}
///|
fn write_port(output : Output, port : Port) -> Unit raise GraphError {
let attributes = [plain_attribute("name", port.name)]
attributes.append(port.extra)
output.graphml_start("port", attributes, namespaces=port.namespaces)
write_description(output, port.description)
write_data(output, port.data)
for nested in port.ports {
write_port(output, nested)
}
output.end("port")
}
///|
fn write_node(output : Output, node : Node) -> Unit raise GraphError {
let attributes = [plain_attribute("id", node.id)]
attributes.append(node.extra)
output.graphml_start("node", attributes, namespaces=node.namespaces)
write_description(output, node.description)
match node.locator {
Some(locator) => write_locator(output, locator)
None => {
write_data(output, node.data)
for port in node.ports {
write_port(output, port)
}
if node.graph is Some(graph) {
write_graph(output, graph)
}
}
}
output.end("node")
}
///|
fn write_edge(output : Output, edge : Edge) -> Unit raise GraphError {
let attributes = [
plain_attribute("source", edge.source),
plain_attribute("target", edge.target),
]
optional_attribute(attributes, "id", edge.id)
optional_attribute(attributes, "sourceport", edge.source_port)
optional_attribute(attributes, "targetport", edge.target_port)
if edge.directed is Some(value) {
attributes.push(
plain_attribute("directed", if value { "true" } else { "false" }),
)
}
attributes.append(edge.extra)
output.graphml_start("edge", attributes, namespaces=edge.namespaces)
write_description(output, edge.description)
write_data(output, edge.data)
if edge.graph is Some(graph) {
write_graph(output, graph)
}
output.end("edge")
}
///|
fn write_endpoint(
output : Output,
endpoint : Endpoint,
) -> Unit raise GraphError {
let attributes = [
plain_attribute("node", endpoint.node),
plain_attribute("type", endpoint.kind.name()),
]
optional_attribute(attributes, "id", endpoint.id)
optional_attribute(attributes, "port", endpoint.port)
attributes.append(endpoint.extra)
output.graphml_start("endpoint", attributes, namespaces=endpoint.namespaces)
write_description(output, endpoint.description)
output.end("endpoint")
}
///|
fn write_hyperedge(
output : Output,
hyperedge : Hyperedge,
) -> Unit raise GraphError {
let attributes = []
optional_attribute(attributes, "id", hyperedge.id)
attributes.append(hyperedge.extra)
output.graphml_start("hyperedge", attributes, namespaces=hyperedge.namespaces)
write_description(output, hyperedge.description)
write_data(output, hyperedge.data)
for endpoint in hyperedge.endpoints {
write_endpoint(output, endpoint)
}
if hyperedge.graph is Some(graph) {
write_graph(output, graph)
}
output.end("hyperedge")
}
///|
fn write_graph(output : Output, graph : Graph) -> Unit raise GraphError {
let attributes = [plain_attribute("edgedefault", graph.edge_default.name())]
optional_attribute(attributes, "id", graph.id)
// Canonical output groups all nodes before edges; refresh its advisory order hint.
attributes.append(
graph.extra.map(fn(attribute) {
if attribute.namespace_uri is None && attribute.name == "parse.order" {
{ ..attribute, value: "nodesfirst", }
} else {
attribute
}
}),
)
output.graphml_start("graph", attributes, namespaces=graph.namespaces)
write_description(output, graph.description)
match graph.locator {
Some(locator) => write_locator(output, locator)
None => {
write_data(output, graph.data)
for node in graph.nodes {
write_node(output, node)
}
for edge in graph.edges {
write_edge(output, edge)
}
for hyperedge in graph.hyperedges {
write_hyperedge(output, hyperedge)
}
}
}
output.end("graph")
}
///|
/// Serialize the supported GraphML information model, not its original XML spelling.
pub fn serialize(
doc : Document,
limits~ : Limits = Limits::default(),
) -> String raise GraphError {
limits.validate()
let output = Output::new(limits)
output.raw("")
output.graphml_start("graphml", doc.extra, namespaces=doc.namespaces)
write_description(output, doc.description)
for key in doc.keys {
write_key(output, key)
}
write_data(output, doc.data)
for graph in doc.graphs {
write_graph(output, graph)
}
output.end("graphml")
output.finish()
}