由于每行的字段数可能会发生变化并且您使用的是 SWI-Prolog,因此我相信使用库record
(Wielemaker & O'Keefe)是一个很好的方法。它允许指定谓词参数的子集并执行类型检查,尽早发现一些潜在的错误。
由于我在这里不知道您的 XML 架构,因此我指定了 3 个示例字段参数:
apl_id
的类型integer
。
dns_id
具有默认值0
和非负整数类型(即nonneg
)。
apl_naam_kort
的类型atom
。
record/1
使用附加字段名称扩展声明很容易。dynamic/1
必须相应地提高声明的重要性。
由于 SWI-Prolog 带有非常好的 Web 标准支持(为此使用 SWI 是明智的选择!)它可以直接从文件加载 XML DOM(即,load_xml/3
)并使用类似 XPath 的语句(即,xpath/3
)。
:- module(fact_file, [load_fact_file/1]).
:- use_module(library(record)).
:- use_module(library(sgml)).
:- use_module(library(xpath)).
:- record(apps(apl_id:integer, dns_id:nonneg=0, apl_naam_kort)).
:- dynamic(apps/3).
load_fact_file(File):-
load_xml(File, Dom, []),
forall(
xpath(Dom, //row, Row),
(
findall(
NVPair,
(
xpath(Row, //field(@name=Name,text), Value1),
value_conversion(Value1, Value2),
NVPair =.. [Name,Value2]
),
NVPairs
),
make_apps(NVPairs, Apps),
assertz(Apps)
)
).
value_conversion(Atom, Number):-
atom_number(Atom, Number), !.
value_conversion(Atom, Atom).
示例使用:
?- load_fact_file(<FILE-PATH>\test.xml').
true.
?- listing(apps).
:- dynamic fact_file:apps/3.
fact_file:apps(1, 7, 'Risk').
fact_file:apps(_, 0, 'Low Risk').
fact_file:apps(1, 7, _).
文件内容test.xml
:
<table>
<row>
<field name="apl_id">1</field>
<field name="dns_id">7</field>
<field name="apl_naam_kort">Risk</field>
</row>
<row>
<field name="apl_naam_kort">Low Risk</field>
</row>
<row>
<field name="apl_id">1</field>
<field name="dns_id">7</field>
</row>
</table>
请注意,我们未指定默认值的缺失参数现在显示为未命名变量。这是因为 Prolog 没有null
价值。
以上代码可能的改进:
- 将价值转换集成到库
record
中。
- 除了谓词表示法(即, )之外,还允许
record
以对表示法(即,Name-Value
或)指定库中的字段。这允许我们省略代码行。Name=Value
Name(Value)
NVPair =.. [Name,Value2]
- 可以动态更新
record/1
声明。如果字段名称集非常大、事先不知道和/或随时间变化,则可能需要这样做。
- 如果给出了使用 XML 模式数据类型 (XSD) 的 XML 模式,则可以自动导出值转换,例如
xsd:nonNegativeInteger
-> nonneg
。