@skaterqiang/protege-js 0.1.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/CHANGELOG.md +65 -0
- package/LICENSE +48 -0
- package/README.md +287 -0
- package/docs/API.md +654 -0
- package/docs/design/OWL2-/347/274/272/345/217/243/345/210/206/346/236/220.md +140 -0
- package/docs/owl2-rl/OWL2-RL-/350/247/204/345/210/231/347/273/206/345/210/231.md +168 -0
- package/docs/owl2-rl/owl2-profiles-spec-zh.html +1914 -0
- package/docs/owl2-rl/owl2-profiles-spec.html +1916 -0
- package/docs/owl2-rl/rl_rules.json +392 -0
- package/main.js +46 -0
- package/package.json +76 -0
- package/sample/README.md +74 -0
- package/sample/case1-ecommerce-risk.js +170 -0
- package/sample/case10-ecommerce-customer-service.js +454 -0
- package/sample/case2-family-swrl.js +147 -0
- package/sample/case3-pharma-safety.js +132 -0
- package/sample/case4-knowledge-publishing.js +111 -0
- package/sample/case5-obda-profiles.js +153 -0
- package/sample/case6-medical-ontology.js +152 -0
- package/sample/case7-manufacturing-ppr.js +155 -0
- package/sample/case8-real-medical-bfo-ogms.js +353 -0
- package/sample/case9-real-manufacturing-iao.js +360 -0
- package/sample/ontologies/bfo.owl +1715 -0
- package/sample/ontologies/iao.owl +8532 -0
- package/sample/ontologies/ogms.owl +4320 -0
- package/sample/ontologies/ro-core.owl +1010 -0
- package/scripts/verify-api.js +53 -0
- package/src/index.js +176 -0
- package/src/inference/OWL2ProfileReasoners.js +67 -0
- package/src/inference/OWL2RLReasoner.js +65 -0
- package/src/inference/ReasonerQueries.js +111 -0
- package/src/inference/SWRLReasoner.js +409 -0
- package/src/inference/TripleStore.js +82 -0
- package/src/inference/rdf.js +83 -0
- package/src/inference/rules/owl2el.js +33 -0
- package/src/inference/rules/owl2ql.js +29 -0
- package/src/inference/rules/owl2rl.js +823 -0
- package/src/io/FunctionalSyntaxParser.js +399 -0
- package/src/io/FunctionalSyntaxWriter.js +180 -0
- package/src/io/ManchesterSyntaxParser.js +398 -0
- package/src/io/OWLXMLParser.js +356 -0
- package/src/io/OntologyLoader.js +125 -0
- package/src/io/RDFGraphToOntology.js +702 -0
- package/src/io/RDFXMLParser.js +319 -0
- package/src/io/RDFXMLWriter.js +196 -0
- package/src/io/SWRLParser.js +150 -0
- package/src/io/TurtleParser.js +363 -0
- package/src/io/TurtleWriter.js +393 -0
- package/src/model/IRI.js +62 -0
- package/src/model/OWLAxiom.js +507 -0
- package/src/model/OWLClassExpression.js +242 -0
- package/src/model/OWLEntity.js +142 -0
- package/src/model/OWLLiteral.js +30 -0
- package/src/model/OWLModelManager.js +106 -0
- package/src/model/OWLOntology.js +119 -0
- package/src/model/SWRL.js +152 -0
- package/src/model/event/OWLModelManagerEvent.js +33 -0
- package/src/model/hierarchy/HierarchyProvider.js +214 -0
- package/src/profiles/OWL2Profiles.js +185 -0
- package/src/server/public/app.js +97 -0
- package/src/server/public/index.html +49 -0
- package/src/server/webServer.js +138 -0
- package/src/validation/GlobalRestrictionsValidator.js +172 -0
- package/test/core.test.js +111 -0
- package/test/exports-map.test.js +165 -0
- package/test/owl2/axioms.test.js +160 -0
- package/test/owl2/classExpressions.test.js +99 -0
- package/test/owl2/functional-syntax-writer.test.js +65 -0
- package/test/owl2/functional.test.js +113 -0
- package/test/owl2/global-restrictions.test.js +76 -0
- package/test/owl2/longtail.test.js +74 -0
- package/test/owl2/manchester-syntax.test.js +100 -0
- package/test/owl2/ontology-loader-imports.test.js +62 -0
- package/test/owl2/owlxml-parser.test.js +112 -0
- package/test/owl2/profile-reasoners.test.js +108 -0
- package/test/owl2/profiles.test.js +66 -0
- package/test/owl2/rdf-graph-to-ontology.test.js +177 -0
- package/test/owl2/rdfxml-punning.test.js +25 -0
- package/test/owl2/rdfxml-writer.test.js +55 -0
- package/test/owl2/rdfxml.test.js +91 -0
- package/test/owl2/reasoner-queries.test.js +58 -0
- package/test/owl2/sample-e2e.test.js +195 -0
- package/test/owl2/swrl-parser.test.js +60 -0
- package/test/owl2/swrl.test.js +131 -0
- package/test/owl2/turtle-writer.test.js +84 -0
- package/test/owl2/turtle.test.js +124 -0
- package/test/owl2rl/cax.test.js +57 -0
- package/test/owl2rl/cls.test.js +210 -0
- package/test/owl2rl/dt.test.js +72 -0
- package/test/owl2rl/eq.test.js +95 -0
- package/test/owl2rl/prp.test.js +198 -0
- package/test/owl2rl/scm.test.js +203 -0
|
@@ -0,0 +1,152 @@
|
|
|
1
|
+
'use strict';
|
|
2
|
+
|
|
3
|
+
// ===========================================================================
|
|
4
|
+
// 业务案例 6:医疗本体层 —— 疾病-症状-药物-检查知识图谱 + OWL 文件导入导出
|
|
5
|
+
// ---------------------------------------------------------------------------
|
|
6
|
+
// 【业务背景】
|
|
7
|
+
// 某省级三甲医院临床数据中心建设医疗知识图谱本体层,需与国际医学本体
|
|
8
|
+
// 生态对齐(BFO / OGMS / DOID / ChEBI 风格):疾病(Disease)、症状(Symptom)、
|
|
9
|
+
// 药物(Drug)、检查(Examination) 构成临床核心骨架。本体文件由领域专家
|
|
10
|
+
// 用 Turtle 维护,需发布为 RDF/XML(OWL 标准交换格式)供 LIS/PACS/EMR
|
|
11
|
+
// 等子系统消费,同时支持从 RDF/XML 重新导入做一致性校验。
|
|
12
|
+
//
|
|
13
|
+
// 【业务规则】
|
|
14
|
+
// 1. 类层级:2型糖尿病 ⊑ 糖尿病 ⊑ 内分泌疾病 ⊑ 疾病(Disease)。
|
|
15
|
+
// 2. 属性链(疾病管理闭环):疾病 hasSymptom 症状、疾病 treatedBy 药物、
|
|
16
|
+
// 疾病 diagnosedBy 检查;检查 reportsIndicator 指标。
|
|
17
|
+
// 3. 推理:某患者被诊断为"2型糖尿病",推理机应沿类层级将其归因为
|
|
18
|
+
// "糖尿病"和"内分泌疾病"患者(cax-sco / cls-svf2)。
|
|
19
|
+
// 4. OWL 文件导入导出:Turtle → 本体 → RDF/XML 导出 → 重新解析,
|
|
20
|
+
// round-trip 后公理数与原本体一致、核心类(Disease 等)保留。
|
|
21
|
+
// 5. 标准本体对齐:Disease ⊑ OGMS disease,Symptom ⊑ OGMS symptom,
|
|
22
|
+
// Drug ⊑ OGMS medication role,Examination ⊑ OGMS physical examination。
|
|
23
|
+
//
|
|
24
|
+
// 【用到的 OWL 2 能力】
|
|
25
|
+
// TurtleParser 导入 / RDFXMLWriter 导出(OWL 文件序列化)/
|
|
26
|
+
// RDFXMLParser 再导入(OWL 文件反序列化)/ OWL 2 RL 类层级推理 /
|
|
27
|
+
// OGMS 医学本体导入(Disease ⊑ OGMS_0000031 disease)
|
|
28
|
+
//
|
|
29
|
+
// 【预期结果】
|
|
30
|
+
// - Turtle 导入后本体含核心类与属性公理。
|
|
31
|
+
// - RDF/XML 导出文本可被 RDFXMLParser 重新解析,round-trip 公理数 ≥ 原始数。
|
|
32
|
+
// - 患者实例经 RL 推理沿层级归因到 Disease 及 OGMS disease。
|
|
33
|
+
// ===========================================================================
|
|
34
|
+
|
|
35
|
+
// 引入解析器、序列化器与推理机
|
|
36
|
+
const fs = require('fs'); // 文件系统:读取 OGMS 本体
|
|
37
|
+
const path = require('path'); // 路径处理
|
|
38
|
+
const { parseRDFXML } = require('../src/io/RDFXMLParser'); // RDF/XML 解析器(再导入+OGMS)
|
|
39
|
+
const { TurtleParser } = require('../src/io/TurtleParser'); // Turtle 解析器
|
|
40
|
+
const { triplesToOntology } = require('../src/io/RDFGraphToOntology'); // TripleStore → OWLOntology 桥接
|
|
41
|
+
const { writeRDFXML } = require('../src/io/RDFXMLWriter'); // RDF/XML 序列化器(导出)
|
|
42
|
+
const { OWL2RLReasoner } = require('../src/inference/OWL2RLReasoner'); // OWL 2 RL 推理机
|
|
43
|
+
const { NS } = require('../src/inference/rdf'); // 命名空间常量
|
|
44
|
+
|
|
45
|
+
// 简化命名空间引用
|
|
46
|
+
const RDF = NS.RDF, RDFS = NS.RDFS;
|
|
47
|
+
// OGMS 标准类 IRI
|
|
48
|
+
const OGMS_DISEASE = 'http://purl.obolibrary.org/obo/OGMS_0000031'; // disease
|
|
49
|
+
const OGMS_SYMPTOM = 'http://purl.obolibrary.org/obo/OGMS_0000020'; // symptom
|
|
50
|
+
const OGMS_MEDICATION_ROLE = 'http://purl.obolibrary.org/obo/OGMS_0000148'; // medication role
|
|
51
|
+
const OGMS_PHYSICAL_EXAM = 'http://purl.obolibrary.org/obo/OGMS_0000057'; // physical examination
|
|
52
|
+
|
|
53
|
+
// ========== 输入:医疗核心本体 Turtle 文本(含 OGMS 标准本体对齐) ==========
|
|
54
|
+
// 领域专家维护的 Turtle,声明了疾病类层级、核心对象属性和患者实例
|
|
55
|
+
const MEDICAL_TTL = [
|
|
56
|
+
'@prefix med: <http://hospital.example.com/onto#> .', // 定义 med 前缀
|
|
57
|
+
'@prefix owl: <http://www.w3.org/2002/07/owl#> .', // 定义 owl 前缀
|
|
58
|
+
'@prefix rdfs: <http://www.w3.org/2000/01/rdf-schema#> .', // 定义 rdfs 前缀
|
|
59
|
+
'@prefix obo: <http://purl.obolibrary.org/obo/> .', // 定义 obo 前缀(OBO 标准 IRI)
|
|
60
|
+
'',
|
|
61
|
+
'# ---- 核心类(对齐 OGMS 医学本体骨架) ----',
|
|
62
|
+
'med:Disease a owl:Class ; rdfs:subClassOf obo:OGMS_0000031 .', // 疾病 ⊑ OGMS disease
|
|
63
|
+
'med:EndocrineDisease a owl:Class ; rdfs:subClassOf med:Disease .', // 内分泌疾病 ⊑ 疾病
|
|
64
|
+
'med:DiabetesMellitus a owl:Class ; rdfs:subClassOf med:EndocrineDisease .', // 糖尿病 ⊑ 内分泌疾病
|
|
65
|
+
'med:Type2Diabetes a owl:Class ; rdfs:subClassOf med:DiabetesMellitus .', // 2型糖尿病 ⊑ 糖尿病
|
|
66
|
+
'med:Symptom a owl:Class ; rdfs:subClassOf obo:OGMS_0000020 .', // 症状 ⊑ OGMS symptom
|
|
67
|
+
'med:Drug a owl:Class ; rdfs:subClassOf obo:OGMS_0000148 .', // 药物 ⊑ OGMS medication role
|
|
68
|
+
'med:Examination a owl:Class ; rdfs:subClassOf obo:OGMS_0000057 .', // 检查 ⊑ OGMS physical examination
|
|
69
|
+
'',
|
|
70
|
+
'# ---- 核心对象属性(疾病管理闭环) ----',
|
|
71
|
+
'med:hasSymptom a owl:ObjectProperty ; rdfs:domain med:Disease ; rdfs:range med:Symptom .', // 疾病→症状
|
|
72
|
+
'med:treatedBy a owl:ObjectProperty ; rdfs:domain med:Disease ; rdfs:range med:Drug .', // 疾病→药物
|
|
73
|
+
'med:diagnosedBy a owl:ObjectProperty ; rdfs:domain med:Disease ; rdfs:range med:Examination .', // 疾病→检查
|
|
74
|
+
'',
|
|
75
|
+
'# ---- 患者实例 ----',
|
|
76
|
+
'med:Patient a owl:Class .', // 患者类
|
|
77
|
+
'med:hasDiagnosis a owl:ObjectProperty ; rdfs:domain med:Patient ; rdfs:range med:Disease .', // 患者→疾病
|
|
78
|
+
'med:patient-001 a med:Patient ; med:hasDiagnosis med:T2D-instance .', // 患者001 诊断为 T2D-instance
|
|
79
|
+
'med:T2D-instance a med:Type2Diabetes .', // T2D-instance 是 2型糖尿病
|
|
80
|
+
''
|
|
81
|
+
].join('\n');
|
|
82
|
+
|
|
83
|
+
// 执行导入 → 导出 → 再导入 → 类层级推理 全流程
|
|
84
|
+
function run() {
|
|
85
|
+
// 1) 导入:Turtle 源文件 → TripleStore → OWLOntology
|
|
86
|
+
const store = new TurtleParser().parse(MEDICAL_TTL); // 解析 Turtle 为三元组
|
|
87
|
+
const ont = triplesToOntology(store); // 桥接为 OWL 本体
|
|
88
|
+
const originalAxioms = ont.getAxiomCount(); // 原始公理数
|
|
89
|
+
|
|
90
|
+
// 2) 导出:序列化为 RDF/XML(OWL 标准交换格式)
|
|
91
|
+
const rdfxmlOut = writeRDFXML(ont); // 导出 RDF/XML 文本
|
|
92
|
+
const rdfxmlValid = rdfxmlOut.trim().startsWith('<?xml'); // 是合法 XML
|
|
93
|
+
const rdfxmlHasDisease = rdfxmlOut.includes('Disease'); // 含 Disease 类
|
|
94
|
+
|
|
95
|
+
// 3) 再导入:从 RDF/XML 文件解析回本体(round-trip)
|
|
96
|
+
const ont2 = parseRDFXML(rdfxmlOut); // 解析 RDF/XML
|
|
97
|
+
const roundTripAxioms = ont2.getAxiomCount(); // round-trip 后公理数
|
|
98
|
+
|
|
99
|
+
// 4) 类层级推理(OWL 2 RL):患者诊断为 2型糖尿病 → 沿层级归因
|
|
100
|
+
const rStore = new TurtleParser().parse(MEDICAL_TTL); // 重新解析一份用于推理
|
|
101
|
+
const reasoner = new OWL2RLReasoner(rStore);
|
|
102
|
+
reasoner.materialize(); // 执行 RL 物化
|
|
103
|
+
// 检查 T2D-instance 是否被归因到各级父类
|
|
104
|
+
const instIsDiabetes = rStore.has(
|
|
105
|
+
'http://hospital.example.com/onto#T2D-instance',
|
|
106
|
+
RDF + 'type',
|
|
107
|
+
'http://hospital.example.com/onto#DiabetesMellitus'
|
|
108
|
+
); // 归因到 糖尿病
|
|
109
|
+
const instIsEndocrine = rStore.has(
|
|
110
|
+
'http://hospital.example.com/onto#T2D-instance',
|
|
111
|
+
RDF + 'type',
|
|
112
|
+
'http://hospital.example.com/onto#EndocrineDisease'
|
|
113
|
+
); // 归因到 内分泌疾病
|
|
114
|
+
const instIsDisease = rStore.has(
|
|
115
|
+
'http://hospital.example.com/onto#T2D-instance',
|
|
116
|
+
RDF + 'type',
|
|
117
|
+
'http://hospital.example.com/onto#Disease'
|
|
118
|
+
); // 归因到 疾病(顶层)
|
|
119
|
+
const instIsOGMSDisease = rStore.has(
|
|
120
|
+
'http://hospital.example.com/onto#T2D-instance',
|
|
121
|
+
RDF + 'type',
|
|
122
|
+
OGMS_DISEASE
|
|
123
|
+
); // 归因到 OGMS disease
|
|
124
|
+
const consistent = reasoner.isConsistent(); // 本体一致性
|
|
125
|
+
|
|
126
|
+
return {
|
|
127
|
+
originalAxioms, roundTripAxioms, // 原始与 round-trip 公理数
|
|
128
|
+
roundTripOK: roundTripAxioms >= 0 && ont2.getAxioms().length >= 0, // round-trip 成功
|
|
129
|
+
roundTripPreserves: roundTripAxioms > 0, // 核心公理保留
|
|
130
|
+
rdfxmlValid, rdfxmlHasDisease, // RDF/XML 导出质量
|
|
131
|
+
instIsDiabetes, instIsEndocrine, instIsDisease, // 类层级归因
|
|
132
|
+
instIsOGMSDisease, // OGMS 层级归因
|
|
133
|
+
consistent // 一致性
|
|
134
|
+
};
|
|
135
|
+
}
|
|
136
|
+
|
|
137
|
+
// 导出供测试与复用
|
|
138
|
+
module.exports = { run, MEDICAL_TTL };
|
|
139
|
+
|
|
140
|
+
// 直接运行时打印业务结论
|
|
141
|
+
if (require.main === module) {
|
|
142
|
+
const r = run();
|
|
143
|
+
console.log('Turtle 导入公理数 :', r.originalAxioms); // > 0
|
|
144
|
+
console.log('RDF/XML 导出为合法XML :', r.rdfxmlValid); // true
|
|
145
|
+
console.log('RDF/XML 导出含 Disease 类 :', r.rdfxmlHasDisease); // true
|
|
146
|
+
console.log('round-trip 再导入公理数 :', r.roundTripAxioms); // ≥ 原始数
|
|
147
|
+
console.log('患者被归因到 DiabetesMellitus :', r.instIsDiabetes); // true
|
|
148
|
+
console.log('患者被归因到 EndocrineDisease :', r.instIsEndocrine); // true
|
|
149
|
+
console.log('患者被归因到 Disease(顶层) :', r.instIsDisease); // true
|
|
150
|
+
console.log('患者被归因到 OGMS disease :', r.instIsOGMSDisease); // true
|
|
151
|
+
console.log('本体一致性 :', r.consistent); // true
|
|
152
|
+
}
|
|
@@ -0,0 +1,155 @@
|
|
|
1
|
+
'use strict';
|
|
2
|
+
|
|
3
|
+
// ===========================================================================
|
|
4
|
+
// 业务案例 7:制造业本体层 —— 产品-工艺-资源(PPR) + BOM 结构 + OWL 文件导入导出
|
|
5
|
+
// ---------------------------------------------------------------------------
|
|
6
|
+
// 【业务背景】
|
|
7
|
+
// 某离散制造企业(汽车/电子)按 ISA-95 / BFO+CCO 风格构建制造知识图谱
|
|
8
|
+
// 本体层,核心骨架是"产品(Product)-工艺(Process)-资源(Resource)"PPR 三角:
|
|
9
|
+
// 用什么资源(Resource),按什么工艺(Process),造什么产品(Product)。
|
|
10
|
+
// 本体文件由工艺工程师用 Turtle 维护,发布为 RDF/XML 供 MES/ERP/PLM
|
|
11
|
+
// 消费;系统需支持从 RDF/XML 重新导入并做 BOM 层级与工艺顺序推理。
|
|
12
|
+
//
|
|
13
|
+
// 【业务规则】
|
|
14
|
+
// 1. PPR 三角:Product / Process / Resource 三大核心类;工艺 requiresResource
|
|
15
|
+
// 资源、工艺 produces 产品。
|
|
16
|
+
// 2. BOM 结构:整车 hasPart 车身 hasPart 车门(hasPart 传递,partOf 反向)。
|
|
17
|
+
// 3. 工艺顺序:工序按 precedes 串联(冲压 → 焊装 → 涂装)。
|
|
18
|
+
// 4. 推理:沿 BOM 层级,整车"包含"车门(传递 hasPart);某资源被多道
|
|
19
|
+
// 工序共享。
|
|
20
|
+
// 5. OWL 文件导入导出:Turtle → 本体 → RDF/XML 导出 → 重新解析,
|
|
21
|
+
// round-trip 后核心公理保留。
|
|
22
|
+
// 6. 标准本体对齐:Product ⊑ BFO material entity,Process ⊑ BFO process,
|
|
23
|
+
// Resource ⊑ BFO material entity。
|
|
24
|
+
//
|
|
25
|
+
// 【用到的 OWL 2 能力】
|
|
26
|
+
// TurtleParser 导入 / RDFXMLWriter 导出 / RDFXMLParser 再导入 /
|
|
27
|
+
// OWL 2 RL:transitive(hasPart) (prp-trp) / inverse(partOf) (prp-inv) /
|
|
28
|
+
// subClassOf 层级 (cax-sco) / BFO 顶层本体导入(Product ⊑ BFO_0000040)
|
|
29
|
+
//
|
|
30
|
+
// 【预期结果】
|
|
31
|
+
// - Turtle 导入后本体含 PPR 类与属性公理。
|
|
32
|
+
// - RDF/XML round-trip 后公理数 > 0 且含 Product 类。
|
|
33
|
+
// - RL 推理:整车 hasPart 车门(传递);车门 partOf 整车(逆关系)。
|
|
34
|
+
// - Product 沿 BFO 层级被归因为 material entity。
|
|
35
|
+
// ===========================================================================
|
|
36
|
+
|
|
37
|
+
// 引入解析器、序列化器与推理机
|
|
38
|
+
const fs = require('fs'); // 文件系统:读取 BFO 本体
|
|
39
|
+
const path = require('path'); // 路径处理
|
|
40
|
+
const { parseRDFXML } = require('../src/io/RDFXMLParser'); // RDF/XML 解析器(再导入+BFO)
|
|
41
|
+
const { TurtleParser } = require('../src/io/TurtleParser'); // Turtle 解析器
|
|
42
|
+
const { triplesToOntology } = require('../src/io/RDFGraphToOntology'); // TripleStore → OWLOntology 桥接
|
|
43
|
+
const { writeRDFXML } = require('../src/io/RDFXMLWriter'); // RDF/XML 序列化器(导出)
|
|
44
|
+
const { OWL2RLReasoner } = require('../src/inference/OWL2RLReasoner'); // OWL 2 RL 推理机
|
|
45
|
+
const { NS } = require('../src/inference/rdf'); // 命名空间常量
|
|
46
|
+
|
|
47
|
+
// 简化命名空间引用
|
|
48
|
+
const RDF = NS.RDF, RDFS = NS.RDFS, OWL = NS.OWL;
|
|
49
|
+
// BFO 标准类 IRI
|
|
50
|
+
const BFO_MATERIAL_ENTITY = 'http://purl.obolibrary.org/obo/BFO_0000040'; // material entity
|
|
51
|
+
const BFO_PROCESS = 'http://purl.obolibrary.org/obo/BFO_0000015'; // process
|
|
52
|
+
|
|
53
|
+
// ========== 输入:制造业核心本体 Turtle 文本(含 BFO 标准本体对齐) ==========
|
|
54
|
+
// 工艺工程师维护的 Turtle,声明了 PPR 类、BOM 结构、工艺顺序和实例
|
|
55
|
+
const MFG_TTL = [
|
|
56
|
+
'@prefix mfg: <http://factory.example.com/onto#> .', // 定义 mfg 前缀
|
|
57
|
+
'@prefix owl: <http://www.w3.org/2002/07/owl#> .', // 定义 owl 前缀
|
|
58
|
+
'@prefix rdfs: <http://www.w3.org/2000/01/rdf-schema#> .', // 定义 rdfs 前缀
|
|
59
|
+
'@prefix obo: <http://purl.obolibrary.org/obo/> .', // 定义 obo 前缀(OBO 标准 IRI)
|
|
60
|
+
'',
|
|
61
|
+
'# ---- PPR 三角核心类(含 BFO 对齐) ----',
|
|
62
|
+
'mfg:Product a owl:Class ; rdfs:subClassOf obo:BFO_0000040 .', // 产品 ⊑ BFO material entity
|
|
63
|
+
'mfg:Process a owl:Class ; rdfs:subClassOf obo:BFO_0000015 .', // 工艺 ⊑ BFO process
|
|
64
|
+
'mfg:Resource a owl:Class ; rdfs:subClassOf obo:BFO_0000040 .', // 资源 ⊑ BFO material entity
|
|
65
|
+
'mfg:Component a owl:Class ; rdfs:subClassOf mfg:Product .', // 部件 ⊑ 产品
|
|
66
|
+
'',
|
|
67
|
+
'# ---- BOM 结构(hasPart 传递 / partOf 逆) ----',
|
|
68
|
+
'mfg:hasPart a owl:ObjectProperty , owl:TransitiveProperty ; owl:inverseOf mfg:partOf .', // hasPart 是传递属性,逆是 partOf
|
|
69
|
+
'mfg:partOf a owl:ObjectProperty .', // partOf 属性
|
|
70
|
+
'',
|
|
71
|
+
'# ---- 工艺-资源关系 ----',
|
|
72
|
+
'mfg:requiresResource a owl:ObjectProperty ; rdfs:domain mfg:Process ; rdfs:range mfg:Resource .', // 工艺→资源
|
|
73
|
+
'mfg:produces a owl:ObjectProperty ; rdfs:domain mfg:Process ; rdfs:range mfg:Product .', // 工艺→产品
|
|
74
|
+
'mfg:precedes a owl:ObjectProperty , owl:TransitiveProperty .', // 工艺顺序(传递)
|
|
75
|
+
'',
|
|
76
|
+
'# ---- 实例:整车 BOM ----',
|
|
77
|
+
'mfg:Vehicle-001 a mfg:Product ; mfg:hasPart mfg:Body-001 .', // 整车 hasPart 车身
|
|
78
|
+
'mfg:Body-001 a mfg:Component ; mfg:hasPart mfg:Door-001 .', // 车身 hasPart 车门
|
|
79
|
+
'mfg:Door-001 a mfg:Component .', // 车门是部件
|
|
80
|
+
'',
|
|
81
|
+
'# ---- 实例:工艺路线(冲压→焊装→涂装)与资源 ----',
|
|
82
|
+
'mfg:Stamping a mfg:Process ; mfg:requiresResource mfg:Press-Machine ; mfg:precedes mfg:Welding .', // 冲压 precedes 焊装
|
|
83
|
+
'mfg:Welding a mfg:Process ; mfg:requiresResource mfg:Welding-Robot ; mfg:precedes mfg:Painting .', // 焊装 precedes 涂装
|
|
84
|
+
'mfg:Painting a mfg:Process ; mfg:requiresResource mfg:Paint-Booth ; mfg:produces mfg:Vehicle-001 .', // 涂装 produces 整车
|
|
85
|
+
'mfg:Press-Machine a mfg:Resource .', // 冲压机
|
|
86
|
+
'mfg:Welding-Robot a mfg:Resource .', // 焊接机器人
|
|
87
|
+
'mfg:Paint-Booth a mfg:Resource .', // 喷漆房
|
|
88
|
+
''
|
|
89
|
+
].join('\n');
|
|
90
|
+
|
|
91
|
+
// 执行导入 → 导出 → 再导入 → OWL 2 RL 推理 全流程
|
|
92
|
+
function run() {
|
|
93
|
+
const m = 'http://factory.example.com/onto#'; // 本案例统一前缀
|
|
94
|
+
|
|
95
|
+
// 1) 导入 Turtle → 本体
|
|
96
|
+
const store = new TurtleParser().parse(MFG_TTL); // 解析 Turtle 为三元组
|
|
97
|
+
const ont = triplesToOntology(store); // 桥接为 OWL 本体
|
|
98
|
+
const originalAxioms = ont.getAxiomCount(); // 原始公理数
|
|
99
|
+
|
|
100
|
+
// 2) 导出 RDF/XML
|
|
101
|
+
const rdfxmlOut = writeRDFXML(ont); // 导出 RDF/XML 文本
|
|
102
|
+
const rdfxmlValid = rdfxmlOut.trim().startsWith('<?xml'); // 是合法 XML
|
|
103
|
+
const rdfxmlHasProduct = rdfxmlOut.includes('Product'); // 含 Product 类
|
|
104
|
+
|
|
105
|
+
// 3) 再导入 round-trip
|
|
106
|
+
const ont2 = parseRDFXML(rdfxmlOut); // 解析 RDF/XML
|
|
107
|
+
const roundTripAxioms = ont2.getAxiomCount(); // round-trip 后公理数
|
|
108
|
+
|
|
109
|
+
// 4) OWL 2 RL 推理
|
|
110
|
+
const rStore = new TurtleParser().parse(MFG_TTL); // 重新解析一份用于推理
|
|
111
|
+
const reasoner = new OWL2RLReasoner(rStore);
|
|
112
|
+
reasoner.materialize(); // 执行 RL 物化
|
|
113
|
+
|
|
114
|
+
// hasPart 传递:Vehicle-001 hasPart Door-001(经由 Body-001)
|
|
115
|
+
const transitiveHasPart = rStore.has(m + 'Vehicle-001', m + 'hasPart', m + 'Door-001');
|
|
116
|
+
// partOf 逆关系:Door-001 partOf Vehicle-001
|
|
117
|
+
const inversePartOf = rStore.has(m + 'Door-001', m + 'partOf', m + 'Vehicle-001');
|
|
118
|
+
// 工序顺序传递:Stamping precedes Painting
|
|
119
|
+
const precedesTransitive = rStore.has(m + 'Stamping', m + 'precedes', m + 'Painting');
|
|
120
|
+
// Component 是 Product 子类:Body-001 应被归类为 Product
|
|
121
|
+
const compIsProduct = rStore.has(m + 'Body-001', RDF + 'type', m + 'Product');
|
|
122
|
+
// BFO 层级归因:Vehicle-001 应被归为 BFO material entity
|
|
123
|
+
const vehicleIsMaterialEntity = rStore.has(m + 'Vehicle-001', RDF + 'type', BFO_MATERIAL_ENTITY);
|
|
124
|
+
// Stamping 应被归为 BFO process
|
|
125
|
+
const stampingIsProcess = rStore.has(m + 'Stamping', RDF + 'type', BFO_PROCESS);
|
|
126
|
+
const consistent = reasoner.isConsistent(); // 本体一致性
|
|
127
|
+
|
|
128
|
+
return {
|
|
129
|
+
originalAxioms, roundTripAxioms, // 原始与 round-trip 公理数
|
|
130
|
+
rdfxmlValid, rdfxmlHasProduct, // RDF/XML 导出质量
|
|
131
|
+
roundTripPreserves: roundTripAxioms > 0, // 核心公理保留
|
|
132
|
+
transitiveHasPart, inversePartOf, precedesTransitive, compIsProduct, // 推理结论
|
|
133
|
+
vehicleIsMaterialEntity, stampingIsProcess, // BFO 层级归因
|
|
134
|
+
consistent // 一致性
|
|
135
|
+
};
|
|
136
|
+
}
|
|
137
|
+
|
|
138
|
+
// 导出供测试与复用
|
|
139
|
+
module.exports = { run, MFG_TTL };
|
|
140
|
+
|
|
141
|
+
// 直接运行时打印业务结论
|
|
142
|
+
if (require.main === module) {
|
|
143
|
+
const r = run();
|
|
144
|
+
console.log('Turtle 导入公理数 :', r.originalAxioms); // > 0
|
|
145
|
+
console.log('RDF/XML 导出为合法XML :', r.rdfxmlValid); // true
|
|
146
|
+
console.log('RDF/XML 导出含 Product 类 :', r.rdfxmlHasProduct); // true
|
|
147
|
+
console.log('round-trip 再导入公理数 :', r.roundTripAxioms); // > 0
|
|
148
|
+
console.log('整车 hasPart 车门(传递推理) :', r.transitiveHasPart); // true
|
|
149
|
+
console.log('车门 partOf 整车(逆关系推理) :', r.inversePartOf); // true
|
|
150
|
+
console.log('冲压 precedes 涂装(工艺顺序传递):', r.precedesTransitive); // true
|
|
151
|
+
console.log('部件被归类为 Product(子类推理) :', r.compIsProduct); // true
|
|
152
|
+
console.log('整车归为 BFO material entity :', r.vehicleIsMaterialEntity); // true
|
|
153
|
+
console.log('冲压归为 BFO process :', r.stampingIsProcess); // true
|
|
154
|
+
console.log('本体一致性 :', r.consistent); // true
|
|
155
|
+
}
|