Skip to content

fix: extract rdfs:subClassOf hierarchies as relationships (Brick follow-up) - #102

Open
Mathew Benjamin (mathewtbenjamin) wants to merge 2 commits into
microsoft:mainfrom
mathewtbenjamin:fix/subclassof-relationships
Open

fix: extract rdfs:subClassOf hierarchies as relationships (Brick follow-up)#102
Mathew Benjamin (mathewtbenjamin) wants to merge 2 commits into
microsoft:mainfrom
mathewtbenjamin:fix/subclassof-relationships

Conversation

@mathewtbenjamin

Copy link
Copy Markdown

Summary

Fixes #101 — after #96 makes the Brick import succeed, the resulting graph is 1,530 fully disconnected nodes: 0 relationships.

Root cause: the relationship mapper only builds edges from owl:ObjectProperty elements carrying rdfs:domain/rdfs:range pairs. Brick 1.4 has just 2 rdfs:domain / 5 rdfs:range statements in the whole 5.2 MB file. Its actual graph structure is the class taxonomy — 2,016 rdfs:subClassOf statements between classes — which the parser dropped entirely. This affects any taxonomy-shaped ontology, not just Brick.

Changes

  • getChildResources() (new helper in src/lib/rdf/parser.ts): plural counterpart of getChildResource() — collects every rdf:resource reference for a child local name, since a class may declare multiple parents.
  • subClassOf extraction pass: after class extraction, each rdfs:subClassOf reference whose target was imported as an entity becomes a many-to-one relationship named subClassOf (id <sub>-subClassOf-<super>). Deliberately conservative:
    • external parents (owl:Thing, other vocabularies) are skipped — no dangling edges;
    • nested owl:Restriction forms (no rdf:resource) are ignored gracefully;
    • self-references and duplicate edges are deduped.
  • 7 new tests: typed-node + rdf:Description syntaxes, multiple inheritance, external-parent/self-reference/duplicate skipping, owl:Restriction tolerance, and coexistence with object-property relationships.

Validation

  • npx tsc --noEmit — clean
  • npx eslint on touched files — clean
  • npx vitest run — 24 files, 408/408 tests pass (7 new)
  • Real-world check: Brick 1.4 RDF/XML (5.2 MB) now parses to 1,530 entities with 1,739 subClassOf relationships connecting 1,525 of them (previously 0), no duplicate relationship ids, parse time unchanged (~7s under jsdom)

Notes

Importing the Brick ontology (and any ontology serialized by rdflib or
similar tools) failed with 'No ontology metadata or OWL classes found'.
The parser only recognized typed node elements (<owl:Class rdf:about>),
but many serializers emit the equivalent rdf:Description form:

  <rdf:Description rdf:about='...'>
    <rdf:type rdf:resource='http://www.w3.org/2002/07/owl#Class'/>
  </rdf:Description>

Brick 1.4's official RDF/XML declares all 1,530 classes this way and
contains zero typed elements.

- Add getTypedElements(): collects both typed node elements and
  rdf:Description elements typed via rdf:type, used for owl:Ontology,
  owl:Class, owl:DatatypeProperty and owl:ObjectProperty extraction.
- Detect Turtle input (@prefix/@base) and raise a clear, actionable
  error instead of 'Malformed XML' (brickschema.org defaults to .ttl).
- Replace the live getElementsByTagName('*') collection in the
  DataBinding scan with a static querySelectorAll('*') snapshot;
  repeated indexed access on live collections is quadratic in some DOM
  implementations, making large imports pathologically slow.
- 9 new tests: rdf:Description extraction for all four types, mixed
  syntax dedupe, and Turtle detection.

Verified against Brick 1.4 RDF/XML (5.3 MB): parses to 1,530 entity
types, ontology name 'Brick'.

Fixes microsoft#85
Importing taxonomy-shaped ontologies (e.g. Brick) produced a graph of
fully disconnected nodes: the relationship mapper only used
owl:ObjectProperty rdfs:domain/rdfs:range pairs, and Brick 1.4 carries
just 2 rdfs:domain / 5 rdfs:range statements in the whole file. Its
actual structure is 2,016 rdfs:subClassOf statements between classes,
which the parser ignored entirely.

- Add getChildResources(): collects every rdf:resource reference for a
  given child local name (a class may declare multiple parents).
- After class extraction, emit a many-to-one 'subClassOf' relationship
  for each rdfs:subClassOf reference whose target was imported as an
  entity. External parents (owl:Thing, other vocabularies), nested
  owl:Restriction forms, self-references, and duplicate edges are
  skipped.
- 7 new tests: typed-node + rdf:Description syntaxes, multiple
  inheritance, external-parent/self-reference/duplicate skipping,
  owl:Restriction tolerance, coexistence with object-property
  relationships.

Verified against Brick 1.4 RDF/XML (5.2 MB): 1,530 entities now carry
1,739 subClassOf relationships connecting 1,525 of them (previously 0
relationships), with no duplicate ids and unchanged parse time (~7s
under jsdom).

Fixes microsoft#101
@mathewtbenjamin

Copy link
Copy Markdown
Author

Friendly nudge 🙂 — this PR has been open ~3 weeks, the CLA check is green, and it's currently mergeable with no conflicts. Is there anything I can do to help move it toward review (rebase, split, or extra context)? Happy to help. Thanks!

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

Imported ontologies with rdfs:subClassOf hierarchies have no relationships (Brick: 1,530 entities, 0 edges)

1 participant