Skip to content

Commit 3993c9a

Browse files
committed
feat: better local ontology management
1 parent 598e5e9 commit 3993c9a

1 file changed

Lines changed: 53 additions & 16 deletions

File tree

src/local-ontology.ts

Lines changed: 53 additions & 16 deletions
Original file line numberDiff line numberDiff line change
@@ -234,8 +234,13 @@ export function convertGrapholToTurtle(content: string): string {
234234
turtleLines.push("");
235235
}
236236

237-
const entitiesById = new Map<string, GrapholEntity>();
237+
// Build entity type map (IRI → kind) from diagram nodes, scoping IDs per-diagram
238+
// to avoid cross-diagram ID collisions (each diagram reuses n1, n2, …).
239+
const entitiesByIri = new Map<string, GrapholEntity>();
240+
const emittedEdges = new Set<string>();
241+
238242
for (const diagram of findElements(content, "diagram")) {
243+
const localMap = new Map<string, GrapholEntity>();
239244
for (const node of findElements(diagram.body, "node")) {
240245
const id = node.attrs.id;
241246
const kind = grapholTypeToEntityKind(node.attrs.type);
@@ -248,12 +253,27 @@ export function convertGrapholToTurtle(content: string): string {
248253

249254
const label = normalizeLabel(getTagText(node.body, "label"));
250255
const entity: GrapholEntity = label ? { id, iri, kind, label } : { id, iri, kind };
251-
entitiesById.set(id, entity);
256+
localMap.set(id, entity);
257+
if (!entitiesByIri.has(iri)) entitiesByIri.set(iri, entity);
258+
}
259+
260+
// Process edges within the same diagram using its local ID map
261+
for (const edge of findElements(diagram.body, "edge")) {
262+
const edgeType = (edge.attrs.type ?? "").toLowerCase();
263+
const source = edge.attrs.source ? localMap.get(edge.attrs.source) : undefined;
264+
const target = edge.attrs.target ? localMap.get(edge.attrs.target) : undefined;
265+
if (!source || !target) continue;
266+
const predicate = grapholEdgePredicate(source, target, edgeType);
267+
if (!predicate) continue;
268+
const triple = `<${escapeIri(source.iri)}> ${predicate} <${escapeIri(target.iri)}> .`;
269+
if (emittedEdges.has(triple)) continue;
270+
emittedEdges.add(triple);
271+
turtleLines.push(triple);
252272
}
253273
}
254274

255275
const emittedEntities = new Set<string>();
256-
for (const entity of entitiesById.values()) {
276+
for (const entity of entitiesByIri.values()) {
257277
if (emittedEntities.has(entity.iri)) continue;
258278
emittedEntities.add(entity.iri);
259279
turtleLines.push(`<${escapeIri(entity.iri)}> a ${grapholEntityTypeTriple(entity.kind)} .`);
@@ -264,19 +284,36 @@ export function convertGrapholToTurtle(content: string): string {
264284

265285
if (emittedEntities.size > 0) turtleLines.push("");
266286

267-
const emittedEdges = new Set<string>();
268-
for (const diagram of findElements(content, "diagram")) {
269-
for (const edge of findElements(diagram.body, "edge")) {
270-
const edgeType = (edge.attrs.type ?? "").toLowerCase();
271-
const source = edge.attrs.source ? entitiesById.get(edge.attrs.source) : undefined;
272-
const target = edge.attrs.target ? entitiesById.get(edge.attrs.target) : undefined;
273-
if (!source || !target) continue;
274-
const predicate = grapholEdgePredicate(source, target, edgeType);
275-
if (!predicate) continue;
276-
const triple = `<${escapeIri(source.iri)}> ${predicate} <${escapeIri(target.iri)}> .`;
277-
if (emittedEdges.has(triple)) continue;
278-
emittedEdges.add(triple);
279-
turtleLines.push(triple);
287+
// Extract annotations (rdfs:label, rdfs:comment, …) from the <iris> section
288+
const irisSection = findFirstElement(ontology.body, "iris");
289+
if (irisSection) {
290+
const emittedAnnotations = new Set<string>();
291+
for (const iriEl of findElements(irisSection.body, "iri")) {
292+
const iriValue = getTagText(iriEl.body, "value");
293+
if (!iriValue || !/^https?:\/\//i.test(iriValue)) continue;
294+
const annotationsEl = findFirstElement(iriEl.body, "annotations");
295+
if (!annotationsEl) continue;
296+
for (const ann of findElements(annotationsEl.body, "annotation")) {
297+
const property = getTagText(ann.body, "property");
298+
if (!property) continue;
299+
const lexicalForm = getTagText(ann.body, "lexicalForm");
300+
if (!lexicalForm) continue;
301+
const language = getTagText(ann.body, "language");
302+
const datatype = getTagText(ann.body, "datatype");
303+
const escaped = escapeTurtleLiteral(lexicalForm);
304+
let objectLiteral: string;
305+
if (language && language.trim()) {
306+
objectLiteral = `"${escaped}"@${language.trim()}`;
307+
} else if (datatype && datatype !== "None" && datatype !== "http://www.w3.org/1999/02/22-rdf-syntax-ns#PlainLiteral") {
308+
objectLiteral = `"${escaped}"^^<${escapeIri(datatype)}>`;
309+
} else {
310+
objectLiteral = `"${escaped}"`;
311+
}
312+
const triple = `<${escapeIri(iriValue)}> <${escapeIri(property)}> ${objectLiteral} .`;
313+
if (emittedAnnotations.has(triple)) continue;
314+
emittedAnnotations.add(triple);
315+
turtleLines.push(triple);
316+
}
280317
}
281318
}
282319

0 commit comments

Comments
 (0)