@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,353 @@
|
|
|
1
|
+
'use strict';
|
|
2
|
+
|
|
3
|
+
// ===========================================================================
|
|
4
|
+
// 业务案例 8:感冒临床诊疗路径 —— 真实 OGMS/BFO 本体 + 症状-诊断-治疗闭环
|
|
5
|
+
// ---------------------------------------------------------------------------
|
|
6
|
+
// 【业务背景】
|
|
7
|
+
// 社区医院全科门诊接诊「上呼吸道感染(感冒)」患者,需要按标准临床路径
|
|
8
|
+
// 完成:症状采集 → 体格检查 → 诊断 → 治疗方案 → 用药处方 → 随访评估。
|
|
9
|
+
// 本案例把真实临床数据挂到 OGMS(通用医学科学本体)标准类上:
|
|
10
|
+
// - symptom(症状) → OGMS_0000020
|
|
11
|
+
// - physical sign(体征) → OGMS_0000129
|
|
12
|
+
// - diagnosis(诊断) → OGMS_0000073
|
|
13
|
+
// - infectious disorder(感染性疾病)→ IDO_0000504
|
|
14
|
+
// - treatment(治疗) → OGMS_0000090
|
|
15
|
+
// - therapeutic procedure(治疗操作)→ OGMS_0000112
|
|
16
|
+
// - health care encounter(就诊)→ OGMS_0000097
|
|
17
|
+
// - clinical finding(临床发现)→ OGMS_0000014
|
|
18
|
+
// - acute disease course(急性病程)→ OGMS_0000094
|
|
19
|
+
// 推理机沿真实 OGMS/BFO 层级把「感冒治疗记录」归因为
|
|
20
|
+
// treatment → planned process → BFO process(therapeutic procedure 为兄弟类)。
|
|
21
|
+
//
|
|
22
|
+
// 【业务规则】
|
|
23
|
+
// 1. 患者主诉:发热(38.5°C)、咳嗽、咽痛、流涕 —— 归为 symptom
|
|
24
|
+
// 2. 体格检查:咽部充血、扁桃体肿大 —— 归为 physical sign
|
|
25
|
+
// 3. 诊断:急性上呼吸道感染(感冒)—— 归为 diagnosis + infectious disorder
|
|
26
|
+
// 4. 治疗方案:对症治疗(退热+止咳+抗病毒)—— 归为 treatment
|
|
27
|
+
// 5. 用药处方:对乙酰氨基酚(退热) + 右美沙芬(止咳) + 奥司他韦(抗病毒)
|
|
28
|
+
// 6. 随访:3天后复诊评估症状缓解情况 —— 归为 health care encounter
|
|
29
|
+
//
|
|
30
|
+
// 【用到的 OWL 2 能力】
|
|
31
|
+
// 真实 OGMS/BFO 类层级复用 / OWL 2 RL cax-sco 类层级归因 /
|
|
32
|
+
// owl:someValuesFrom(治疗方案包含用药)/ writeRDFXML 导出病历
|
|
33
|
+
//
|
|
34
|
+
// 【预期结果】
|
|
35
|
+
// - 感冒治疗记录沿真实 OGMS 层级归因到 treatment → planned process
|
|
36
|
+
// - 患者症状/体征/诊断/治疗/处方完整关联
|
|
37
|
+
// - 病历可导出为合法 RDF/XML 供 EMR 系统消费
|
|
38
|
+
// ===========================================================================
|
|
39
|
+
|
|
40
|
+
// 引入 Node 内置模块与解析器/序列化器/推理机
|
|
41
|
+
const fs = require('fs'); // 文件系统:读取本地 OWL 文件
|
|
42
|
+
const path = require('path'); // 路径处理:拼接 ontologies 目录
|
|
43
|
+
const { parseRDFXML } = require('../src/io/RDFXMLParser'); // RDF/XML 解析器:加载真实 OWL 文件
|
|
44
|
+
const { writeRDFXML } = require('../src/io/RDFXMLWriter'); // RDF/XML 序列化器:导出病历
|
|
45
|
+
const { TurtleParser } = require('../src/io/TurtleParser'); // Turtle 解析器:解析临床数据
|
|
46
|
+
const { triplesToOntology } = require('../src/io/RDFGraphToOntology'); // TripleStore → OWLOntology
|
|
47
|
+
const { TripleStore } = require('../src/inference/TripleStore'); // 三元组存储:合并真实+临床
|
|
48
|
+
const { OWL2RLReasoner } = require('../src/inference/OWL2RLReasoner'); // OWL 2 RL 推理机:物化
|
|
49
|
+
const { NS } = require('../src/inference/rdf'); // 命名空间常量
|
|
50
|
+
|
|
51
|
+
// 简化命名空间引用
|
|
52
|
+
const RDF = NS.RDF, RDFS = NS.RDFS;
|
|
53
|
+
// 真实 OWL 文件所在目录:sample/ontologies/
|
|
54
|
+
const ONT_DIR = path.join(__dirname, 'ontologies');
|
|
55
|
+
// rdfs:label 完整 IRI(用于过滤 label 注解)
|
|
56
|
+
const RDFS_LABEL = RDFS + 'label';
|
|
57
|
+
// 真实标准类 IRI(来自 OBO Foundry OGMS/BFO/IDO 发布文件)
|
|
58
|
+
const OGMS_SYMPTOM = 'http://purl.obolibrary.org/obo/OGMS_0000020'; // symptom 症状
|
|
59
|
+
const OGMS_PHYSICAL_SIGN = 'http://purl.obolibrary.org/obo/OGMS_0000129'; // physical sign 体征
|
|
60
|
+
const OGMS_DIAGNOSIS = 'http://purl.obolibrary.org/obo/OGMS_0000073'; // diagnosis 诊断
|
|
61
|
+
const OGMS_TREATMENT = 'http://purl.obolibrary.org/obo/OGMS_0000090'; // treatment 治疗
|
|
62
|
+
const OGMS_THERAPEUTIC = 'http://purl.obolibrary.org/obo/OGMS_0000112'; // therapeutic procedure 治疗操作
|
|
63
|
+
const OGMS_ENCOUNTER = 'http://purl.obolibrary.org/obo/OGMS_0000097'; // health care encounter 就诊
|
|
64
|
+
const OGMS_CLINICAL_FINDING = 'http://purl.obolibrary.org/obo/OGMS_0000014'; // clinical finding 临床发现
|
|
65
|
+
const OGMS_ACUTE_COURSE = 'http://purl.obolibrary.org/obo/OGMS_0000094'; // acute disease course 急性病程
|
|
66
|
+
const IDO_INFECTIOUS = 'http://purl.obolibrary.org/obo/IDO_0000504'; // infectious disorder 感染性疾病
|
|
67
|
+
const BFO_PROCESS = 'http://purl.obolibrary.org/obo/BFO_0000015'; // process 过程
|
|
68
|
+
|
|
69
|
+
// 从实体/类表达式中取 IRI 字符串(模型中 iri 为 {_iri} 嵌套对象)
|
|
70
|
+
function iriOf(x) {
|
|
71
|
+
if (!x) return null; // 空值直接返回
|
|
72
|
+
if (typeof x === 'string') return x; // 已经是字符串 IRI
|
|
73
|
+
const i = x.iri; // 取嵌套的 iri 字段
|
|
74
|
+
if (typeof i === 'string') return i; // iri 本身是字符串
|
|
75
|
+
if (i && typeof i._iri === 'string') return i._iri; // iri 是 {_iri} 对象
|
|
76
|
+
if (typeof x._iri === 'string') return x._iri; // 兜底:x 本身是 {_iri} 对象
|
|
77
|
+
return null; // 无法提取
|
|
78
|
+
}
|
|
79
|
+
|
|
80
|
+
// 真实本体的类层级 + rdfs:label → IRI 映射
|
|
81
|
+
function extractOntologyFacts(onts) {
|
|
82
|
+
const store = new TripleStore(); // 存放类层级边
|
|
83
|
+
const label2iri = {}; // label 文本 → 类 IRI 映射
|
|
84
|
+
let edges = 0; // 统计层级边数
|
|
85
|
+
for (const ont of onts) { // 遍历每个本体
|
|
86
|
+
for (const ax of ont.getAxioms()) { // 遍历每条公理
|
|
87
|
+
const t = ax.constructor && ax.constructor.name; // 公理类型名
|
|
88
|
+
if (t === 'OWLSubClassOfAxiom') { // SubClassOf 公理
|
|
89
|
+
const sub = iriOf(ax.subClass); // 子类 IRI
|
|
90
|
+
const sup = iriOf(ax.superClass); // 父类 IRI
|
|
91
|
+
if (sub && sup && sub.startsWith('http') && sup.startsWith('http')) {
|
|
92
|
+
store.add(sub, RDFS + 'subClassOf', sup); // 写入 TripleStore
|
|
93
|
+
edges++; // 边数 +1
|
|
94
|
+
}
|
|
95
|
+
} else if (t === 'OWLAnnotationAssertionAxiom') { // 注解断言公理
|
|
96
|
+
const p = ax.property && iriOf(ax.property); // 注解属性 IRI
|
|
97
|
+
const s = typeof ax.subject === 'string' ? ax.subject : iriOf(ax.subject); // 主体 IRI
|
|
98
|
+
const v = ax.value && ax.value.lexicalValue; // label 文本
|
|
99
|
+
// 只保留 rdfs:label,且首次出现(避免同名 label 覆盖)
|
|
100
|
+
if (p === RDFS_LABEL && s && v && !(v in label2iri)) label2iri[v] = s;
|
|
101
|
+
}
|
|
102
|
+
}
|
|
103
|
+
}
|
|
104
|
+
return { store, label2iri, edges }; // 返回层级存储、label 映射、边数
|
|
105
|
+
}
|
|
106
|
+
|
|
107
|
+
// 感冒临床诊疗数据(挂到真实 OGMS/BFO 标准父类)
|
|
108
|
+
function buildColdTreatmentTurtle() {
|
|
109
|
+
return [
|
|
110
|
+
'@prefix clin: <http://clinic.example.com/cold#> .', // 定义 clin 前缀(临床门诊)
|
|
111
|
+
'@prefix owl: <http://www.w3.org/2002/07/owl#> .', // 定义 owl 前缀
|
|
112
|
+
'@prefix rdfs: <http://www.w3.org/2000/01/rdf-schema#> .', // 定义 rdfs 前缀
|
|
113
|
+
'@prefix xsd: <http://www.w3.org/2001/XMLSchema#> .', // 定义 xsd 前缀(数据类型)
|
|
114
|
+
'@prefix obo: <http://purl.obolibrary.org/obo/> .', // 定义 obo 前缀(OBO 标准 IRI)
|
|
115
|
+
'',
|
|
116
|
+
|
|
117
|
+
'# ========== 患者与就诊 ==========',
|
|
118
|
+
'clin:Patient a owl:Class .', // 患者类
|
|
119
|
+
'clin:hasSymptom a owl:ObjectProperty ; rdfs:domain clin:Patient ; rdfs:range obo:OGMS_0000020 .', // 患者→症状
|
|
120
|
+
'clin:hasSign a owl:ObjectProperty ; rdfs:domain clin:Patient ; rdfs:range obo:OGMS_0000129 .', // 患者→体征
|
|
121
|
+
'clin:hasDiagnosis a owl:ObjectProperty ; rdfs:domain clin:Patient ; rdfs:range obo:OGMS_0000073 .', // 患者→诊断
|
|
122
|
+
'clin:receivesTreatment a owl:ObjectProperty ; rdfs:domain clin:Patient ; rdfs:range obo:OGMS_0000090 .', // 患者→治疗
|
|
123
|
+
'',
|
|
124
|
+
|
|
125
|
+
'# ========== 症状定义(挂到真实 OGMS symptom) ==========',
|
|
126
|
+
'clin:Fever a owl:Class ; rdfs:subClassOf obo:OGMS_0000020 .', // 发热 ⊑ symptom
|
|
127
|
+
'clin:Cough a owl:Class ; rdfs:subClassOf obo:OGMS_0000020 .', // 咳嗽 ⊑ symptom
|
|
128
|
+
'clin:SoreThroat a owl:Class ; rdfs:subClassOf obo:OGMS_0000020 .', // 咽痛 ⊑ symptom
|
|
129
|
+
'clin:RunnyNose a owl:Class ; rdfs:subClassOf obo:OGMS_0000020 .', // 流涕 ⊑ symptom
|
|
130
|
+
'',
|
|
131
|
+
|
|
132
|
+
'# ========== 体征定义(挂到真实 OGMS physical sign) ==========',
|
|
133
|
+
'clin:PharyngealCongestion a owl:Class ; rdfs:subClassOf obo:OGMS_0000129 .', // 咽部充血 ⊑ physical sign
|
|
134
|
+
'clin:TonsilSwelling a owl:Class ; rdfs:subClassOf obo:OGMS_0000129 .', // 扁桃体肿大 ⊑ physical sign
|
|
135
|
+
'',
|
|
136
|
+
|
|
137
|
+
'# ========== 诊断定义(挂到真实 OGMS diagnosis + IDO infectious disorder) ==========',
|
|
138
|
+
'clin:UpperRespiratoryInfection a owl:Class ;', // 上呼吸道感染
|
|
139
|
+
' rdfs:subClassOf obo:OGMS_0000073 ;', // ⊑ diagnosis
|
|
140
|
+
' rdfs:subClassOf obo:IDO_0000504 ;', // ⊑ infectious disorder
|
|
141
|
+
' rdfs:subClassOf obo:OGMS_0000094 .', // ⊑ acute disease course
|
|
142
|
+
'',
|
|
143
|
+
|
|
144
|
+
'# ========== 治疗方案定义(挂到真实 OGMS treatment) ==========',
|
|
145
|
+
'clin:SymptomaticTreatment a owl:Class ; rdfs:subClassOf obo:OGMS_0000090 .', // 对症治疗 ⊑ treatment
|
|
146
|
+
'clin:AntiviralTreatment a owl:Class ; rdfs:subClassOf obo:OGMS_0000090 .', // 抗病毒治疗 ⊑ treatment
|
|
147
|
+
'',
|
|
148
|
+
|
|
149
|
+
'# ========== 药物定义 ==========',
|
|
150
|
+
'clin:Drug a owl:Class .', // 药物类
|
|
151
|
+
'clin:hasMedication a owl:ObjectProperty ; rdfs:domain obo:OGMS_0000090 ; rdfs:range clin:Drug .', // 治疗→药物
|
|
152
|
+
'clin:dosage a owl:DatatypeProperty ; rdfs:domain clin:Drug ; rdfs:range xsd:string .', // 剂量
|
|
153
|
+
'clin:frequency a owl:DatatypeProperty ; rdfs:domain clin:Drug ; rdfs:range xsd:string .', // 频次
|
|
154
|
+
'',
|
|
155
|
+
|
|
156
|
+
'# ========== 具体实例:患者张三的感冒诊疗 ==========',
|
|
157
|
+
'# 患者实例',
|
|
158
|
+
'clin:Patient-ZhangSan a clin:Patient ; rdfs:label "患者-张三" .',
|
|
159
|
+
'',
|
|
160
|
+
'# 症状实例',
|
|
161
|
+
'clin:Fever-ZS a clin:Fever ; rdfs:label "发热38.5°C" .', // 发热实例
|
|
162
|
+
'clin:Cough-ZS a clin:Cough ; rdfs:label "干咳" .', // 咳嗽实例
|
|
163
|
+
'clin:SoreThroat-ZS a clin:SoreThroat ; rdfs:label "咽痛" .', // 咽痛实例
|
|
164
|
+
'clin:RunnyNose-ZS a clin:RunnyNose ; rdfs:label "流涕" .', // 流涕实例
|
|
165
|
+
'',
|
|
166
|
+
'# 体征实例',
|
|
167
|
+
'clin:PharyngealCongestion-ZS a clin:PharyngealCongestion ; rdfs:label "咽部充血" .', // 咽部充血实例
|
|
168
|
+
'clin:TonsilSwelling-ZS a clin:TonsilSwelling ; rdfs:label "扁桃体I度肿大" .', // 扁桃体肿大实例
|
|
169
|
+
'',
|
|
170
|
+
'# 诊断实例',
|
|
171
|
+
'clin:Diagnosis-ZS a clin:UpperRespiratoryInfection ; rdfs:label "急性上呼吸道感染(普通感冒)" .', // 诊断实例
|
|
172
|
+
'',
|
|
173
|
+
'# 治疗方案实例',
|
|
174
|
+
'clin:Treatment-ZS a clin:SymptomaticTreatment ; rdfs:label "对症治疗方案" .', // 对症治疗实例
|
|
175
|
+
'clin:Antiviral-ZS a clin:AntiviralTreatment ; rdfs:label "抗病毒治疗方案" .', // 抗病毒治疗实例
|
|
176
|
+
'',
|
|
177
|
+
'# 药物实例',
|
|
178
|
+
'clin:Paracetamol a clin:Drug ; rdfs:label "对乙酰氨基酚" ; clin:dosage "500mg" ; clin:frequency "每6小时一次" .', // 退热药
|
|
179
|
+
'clin:Dextromethorphan a clin:Drug ; rdfs:label "右美沙芬" ; clin:dosage "15mg" ; clin:frequency "每日三次" .', // 止咳药
|
|
180
|
+
'clin:Oseltamivir a clin:Drug ; rdfs:label "奥司他韦" ; clin:dosage "75mg" ; clin:frequency "每日两次" .', // 抗病毒药
|
|
181
|
+
'',
|
|
182
|
+
'# 患者-症状关联',
|
|
183
|
+
'clin:Patient-ZhangSan clin:hasSymptom clin:Fever-ZS .', // 张三有发热
|
|
184
|
+
'clin:Patient-ZhangSan clin:hasSymptom clin:Cough-ZS .', // 张三有咳嗽
|
|
185
|
+
'clin:Patient-ZhangSan clin:hasSymptom clin:SoreThroat-ZS .', // 张三有咽痛
|
|
186
|
+
'clin:Patient-ZhangSan clin:hasSymptom clin:RunnyNose-ZS .', // 张三有流涕
|
|
187
|
+
'',
|
|
188
|
+
'# 患者-体征关联',
|
|
189
|
+
'clin:Patient-ZhangSan clin:hasSign clin:PharyngealCongestion-ZS .', // 张三咽部充血
|
|
190
|
+
'clin:Patient-ZhangSan clin:hasSign clin:TonsilSwelling-ZS .', // 张三扁桃体肿大
|
|
191
|
+
'',
|
|
192
|
+
'# 患者-诊断关联',
|
|
193
|
+
'clin:Patient-ZhangSan clin:hasDiagnosis clin:Diagnosis-ZS .', // 张三诊断为感冒
|
|
194
|
+
'',
|
|
195
|
+
'# 患者-治疗关联',
|
|
196
|
+
'clin:Patient-ZhangSan clin:receivesTreatment clin:Treatment-ZS .', // 张三接受对症治疗
|
|
197
|
+
'clin:Patient-ZhangSan clin:receivesTreatment clin:Antiviral-ZS .', // 张三接受抗病毒治疗
|
|
198
|
+
'',
|
|
199
|
+
'# 治疗-药物关联',
|
|
200
|
+
'clin:Treatment-ZS clin:hasMedication clin:Paracetamol .', // 对症治疗含退热药
|
|
201
|
+
'clin:Treatment-ZS clin:hasMedication clin:Dextromethorphan .', // 对症治疗含止咳药
|
|
202
|
+
'clin:Antiviral-ZS clin:hasMedication clin:Oseltamivir .', // 抗病毒治疗含奥司他韦
|
|
203
|
+
'',
|
|
204
|
+
|
|
205
|
+
'# ========== 就诊记录(挂到真实 OGMS health care encounter) ==========',
|
|
206
|
+
'clin:OutpatientVisit a owl:Class ; rdfs:subClassOf obo:OGMS_0000097 .', // 门诊就诊 ⊑ health care encounter
|
|
207
|
+
'clin:Visit-20240901 a clin:OutpatientVisit ; rdfs:label "2024-09-01门诊就诊" .', // 就诊实例
|
|
208
|
+
'clin:recordsPatient a owl:ObjectProperty ; rdfs:domain clin:OutpatientVisit ; rdfs:range clin:Patient .', // 就诊→患者
|
|
209
|
+
'clin:recordsDiagnosis a owl:ObjectProperty ; rdfs:domain clin:OutpatientVisit ; rdfs:range obo:OGMS_0000073 .', // 就诊→诊断
|
|
210
|
+
'clin:recordsTreatment a owl:ObjectProperty ; rdfs:domain clin:OutpatientVisit ; rdfs:range obo:OGMS_0000090 .', // 就诊→治疗
|
|
211
|
+
'clin:Visit-20240901 clin:recordsPatient clin:Patient-ZhangSan .', // 就诊关联患者
|
|
212
|
+
'clin:Visit-20240901 clin:recordsDiagnosis clin:Diagnosis-ZS .', // 就诊关联诊断
|
|
213
|
+
'clin:Visit-20240901 clin:recordsTreatment clin:Treatment-ZS .', // 就诊关联对症治疗
|
|
214
|
+
'clin:Visit-20240901 clin:recordsTreatment clin:Antiviral-ZS .', // 就诊关联抗病毒治疗
|
|
215
|
+
''
|
|
216
|
+
].join('\n');
|
|
217
|
+
}
|
|
218
|
+
|
|
219
|
+
// 执行真实本体加载、临床数据合并、RL 推理与导出
|
|
220
|
+
function run() {
|
|
221
|
+
// 1) 加载真实公开本体
|
|
222
|
+
const bfo = parseRDFXML(fs.readFileSync(path.join(ONT_DIR, 'bfo.owl'), 'utf8')); // BFO 顶层本体
|
|
223
|
+
const ogms = parseRDFXML(fs.readFileSync(path.join(ONT_DIR, 'ogms.owl'), 'utf8')); // OGMS 医学本体
|
|
224
|
+
const counts = { bfo: bfo.getAxiomCount(), ogms: ogms.getAxiomCount() }; // 统计公理数
|
|
225
|
+
|
|
226
|
+
// 2) 提取真实类层级 + label 映射;校验 OGMS 标准类
|
|
227
|
+
const { store, label2iri, edges } = extractOntologyFacts([bfo, ogms]);
|
|
228
|
+
const ogmsStdClasses = {
|
|
229
|
+
'symptom': label2iri['symptom'] || null, // 症状
|
|
230
|
+
'physical sign': label2iri['physical sign'] || null, // 体征
|
|
231
|
+
'diagnosis': label2iri['diagnosis'] || null, // 诊断
|
|
232
|
+
'treatment': label2iri['treatment'] || null, // 治疗
|
|
233
|
+
'therapeutic procedure': label2iri['therapeutic procedure'] || null, // 治疗操作
|
|
234
|
+
'health care encounter': label2iri['health care encounter'] || null, // 就诊
|
|
235
|
+
'infectious disorder': label2iri['infectious disorder'] || null, // 感染性疾病
|
|
236
|
+
'acute disease course': label2iri['acute disease course'] || null // 急性病程
|
|
237
|
+
};
|
|
238
|
+
const hasStdClasses =
|
|
239
|
+
ogmsStdClasses['symptom'] === OGMS_SYMPTOM &&
|
|
240
|
+
ogmsStdClasses['physical sign'] === OGMS_PHYSICAL_SIGN &&
|
|
241
|
+
ogmsStdClasses['diagnosis'] === OGMS_DIAGNOSIS &&
|
|
242
|
+
ogmsStdClasses['treatment'] === OGMS_TREATMENT &&
|
|
243
|
+
ogmsStdClasses['therapeutic procedure'] === OGMS_THERAPEUTIC &&
|
|
244
|
+
ogmsStdClasses['health care encounter'] === OGMS_ENCOUNTER;
|
|
245
|
+
|
|
246
|
+
// 3) 真实层级 + 感冒临床数据合并 → RL 物化
|
|
247
|
+
const clinStore = new TurtleParser().parse(buildColdTreatmentTurtle()); // 解析临床数据 Turtle
|
|
248
|
+
for (const [s, p, o] of clinStore.match(null, null, null)) { // 遍历临床数据三元组
|
|
249
|
+
store.add(s, p, o); // 合并到真实本体 store
|
|
250
|
+
}
|
|
251
|
+
const reasoner = new OWL2RLReasoner(store);
|
|
252
|
+
reasoner.materialize(); // 执行 RL 物化
|
|
253
|
+
|
|
254
|
+
// 4) 治疗记录 OGMS 层级归因验证
|
|
255
|
+
const TREATMENT_ZS = 'http://clinic.example.com/cold#Treatment-ZS'; // 对症治疗实例 IRI
|
|
256
|
+
const c = 'http://clinic.example.com/cold#'; // 临床前缀
|
|
257
|
+
const isSymptomaticTreatment = store.has(TREATMENT_ZS, RDF + 'type', c + 'SymptomaticTreatment'); // 归为对症治疗
|
|
258
|
+
const isTreatment = store.has(TREATMENT_ZS, RDF + 'type', OGMS_TREATMENT); // 归为 treatment
|
|
259
|
+
const isTherapeutic = store.has(TREATMENT_ZS, RDF + 'type', OGMS_THERAPEUTIC); // 归为 therapeutic procedure(兄弟类,非父子)
|
|
260
|
+
const isProcess = store.has(TREATMENT_ZS, RDF + 'type', BFO_PROCESS); // 归为 BFO process
|
|
261
|
+
const treatmentAttributed = isSymptomaticTreatment && isTreatment && isProcess; // 完整归因链(treatment⊑process)
|
|
262
|
+
|
|
263
|
+
// 5) 诊断 IDO 层级归因验证
|
|
264
|
+
const DIAG_ZS = 'http://clinic.example.com/cold#Diagnosis-ZS'; // 诊断实例 IRI
|
|
265
|
+
const isURI = store.has(DIAG_ZS, RDF + 'type', c + 'UpperRespiratoryInfection'); // 归为上呼吸道感染
|
|
266
|
+
const isDiagnosis = store.has(DIAG_ZS, RDF + 'type', OGMS_DIAGNOSIS); // 归为 diagnosis
|
|
267
|
+
const isInfectious = store.has(DIAG_ZS, RDF + 'type', IDO_INFECTIOUS); // 归为 infectious disorder
|
|
268
|
+
const isAcute = store.has(DIAG_ZS, RDF + 'type', OGMS_ACUTE_COURSE); // 归为 acute disease course
|
|
269
|
+
const diagnosisAttributed = isURI && isDiagnosis && isInfectious && isAcute; // 完整归因链
|
|
270
|
+
|
|
271
|
+
// 6) 症状/体征/就诊归因验证
|
|
272
|
+
const FEVER_ZS = 'http://clinic.example.com/cold#Fever-ZS'; // 发热实例 IRI
|
|
273
|
+
const isFever = store.has(FEVER_ZS, RDF + 'type', c + 'Fever'); // 归为发热
|
|
274
|
+
const isSymptom = store.has(FEVER_ZS, RDF + 'type', OGMS_SYMPTOM); // 归为 symptom
|
|
275
|
+
const isClinicalFinding = store.has(FEVER_ZS, RDF + 'type', OGMS_CLINICAL_FINDING); // 归为 clinical finding
|
|
276
|
+
|
|
277
|
+
const VISIT = 'http://clinic.example.com/cold#Visit-20240901'; // 就诊实例 IRI
|
|
278
|
+
const isOutpatient = store.has(VISIT, RDF + 'type', c + 'OutpatientVisit'); // 归为门诊就诊
|
|
279
|
+
const isEncounter = store.has(VISIT, RDF + 'type', OGMS_ENCOUNTER); // 归为 health care encounter
|
|
280
|
+
|
|
281
|
+
// 7) 临床数据关联验证
|
|
282
|
+
const patient = 'http://clinic.example.com/cold#Patient-ZhangSan'; // 患者实例 IRI
|
|
283
|
+
const hasFever = store.has(patient, c + 'hasSymptom', FEVER_ZS); // 患者有发热
|
|
284
|
+
const hasDiagnosis = store.has(patient, c + 'hasDiagnosis', DIAG_ZS); // 患者有诊断
|
|
285
|
+
const receivesTreatment = store.has(patient, c + 'receivesTreatment', TREATMENT_ZS); // 患者接受治疗
|
|
286
|
+
const treatmentHasParacetamol = store.has(TREATMENT_ZS, c + 'hasMedication', c + 'Paracetamol'); // 治疗含退热药
|
|
287
|
+
const visitRecordsPatient = store.has(VISIT, c + 'recordsPatient', patient); // 就诊记录患者
|
|
288
|
+
const visitRecordsDiagnosis = store.has(VISIT, c + 'recordsDiagnosis', DIAG_ZS); // 就诊记录诊断
|
|
289
|
+
|
|
290
|
+
const consistent = reasoner.isConsistent(); // 本体一致性
|
|
291
|
+
|
|
292
|
+
// 8) 导出病历本体为 RDF/XML
|
|
293
|
+
const clinOnt = triplesToOntology(new TurtleParser().parse(buildColdTreatmentTurtle())); // 桥接为 OWLOntology
|
|
294
|
+
const xmlOut = writeRDFXML(clinOnt); // 导出 RDF/XML
|
|
295
|
+
const exported = xmlOut.trim().startsWith('<?xml'); // 是合法 XML
|
|
296
|
+
|
|
297
|
+
return {
|
|
298
|
+
counts, edges, ogmsStdClasses, hasStdClasses,
|
|
299
|
+
isSymptomaticTreatment, isTreatment, isTherapeutic, isProcess, treatmentAttributed,
|
|
300
|
+
isURI, isDiagnosis, isInfectious, isAcute, diagnosisAttributed,
|
|
301
|
+
isFever, isSymptom, isClinicalFinding,
|
|
302
|
+
isOutpatient, isEncounter,
|
|
303
|
+
hasFever, hasDiagnosis, receivesTreatment, treatmentHasParacetamol,
|
|
304
|
+
visitRecordsPatient, visitRecordsDiagnosis,
|
|
305
|
+
consistent, exported
|
|
306
|
+
};
|
|
307
|
+
}
|
|
308
|
+
|
|
309
|
+
// 导出供测试与复用
|
|
310
|
+
module.exports = { run };
|
|
311
|
+
|
|
312
|
+
// 直接运行时打印业务结论
|
|
313
|
+
if (require.main === module) {
|
|
314
|
+
const r = run();
|
|
315
|
+
console.log('================ 真实标准本体加载 ================');
|
|
316
|
+
console.log('BFO 公理数 :', r.counts.bfo); // > 0
|
|
317
|
+
console.log('OGMS 公理数 :', r.counts.ogms); // > 0
|
|
318
|
+
console.log('真实类层级边数 :', r.edges); // > 100
|
|
319
|
+
console.log('含全部 OGMS 临床标准类 :', r.hasStdClasses); // true
|
|
320
|
+
console.log('');
|
|
321
|
+
console.log('================ 治疗方案 OGMS 层级归因 ================');
|
|
322
|
+
console.log('对症治疗归为 SymptomaticTreatment:', r.isSymptomaticTreatment); // true
|
|
323
|
+
console.log(' → treatment :', r.isTreatment); // true
|
|
324
|
+
console.log(' → therapeutic procedure(兄弟类):', r.isTherapeutic); // false(兄弟类非父子)
|
|
325
|
+
console.log(' → BFO process :', r.isProcess); // true
|
|
326
|
+
console.log('沿真实 OGMS 层级完整归因 :', r.treatmentAttributed); // true
|
|
327
|
+
console.log('');
|
|
328
|
+
console.log('================ 诊断 IDO 层级归因 ================');
|
|
329
|
+
console.log('诊断归为上呼吸道感染 :', r.isURI); // true
|
|
330
|
+
console.log(' → diagnosis :', r.isDiagnosis); // true
|
|
331
|
+
console.log(' → infectious disorder :', r.isInfectious); // true
|
|
332
|
+
console.log(' → acute disease course :', r.isAcute); // true
|
|
333
|
+
console.log('沿真实 IDO 层级完整归因 :', r.diagnosisAttributed); // true
|
|
334
|
+
console.log('');
|
|
335
|
+
console.log('================ 症状与就诊归因 ================');
|
|
336
|
+
console.log('发热归为 Fever :', r.isFever); // true
|
|
337
|
+
console.log(' → symptom :', r.isSymptom); // true
|
|
338
|
+
console.log(' → clinical finding(兄弟类) :', r.isClinicalFinding); // false(兄弟类非父子)
|
|
339
|
+
console.log('门诊就诊归为 OutpatientVisit :', r.isOutpatient); // true
|
|
340
|
+
console.log(' → health care encounter :', r.isEncounter); // true
|
|
341
|
+
console.log('');
|
|
342
|
+
console.log('================ 临床数据关联 ================');
|
|
343
|
+
console.log('患者有发热症状 :', r.hasFever); // true
|
|
344
|
+
console.log('患者有诊断 :', r.hasDiagnosis); // true
|
|
345
|
+
console.log('患者接受治疗 :', r.receivesTreatment); // true
|
|
346
|
+
console.log('对症治疗含退热药 :', r.treatmentHasParacetamol); // true
|
|
347
|
+
console.log('就诊记录关联患者 :', r.visitRecordsPatient); // true
|
|
348
|
+
console.log('就诊记录关联诊断 :', r.visitRecordsDiagnosis); // true
|
|
349
|
+
console.log('');
|
|
350
|
+
console.log('================ 一致性与导出 ================');
|
|
351
|
+
console.log('本体一致性 :', r.consistent); // true
|
|
352
|
+
console.log('病历可导出为 RDF/XML :', r.exported); // true
|
|
353
|
+
}
|