1

我的部分配置文件如下:

<factFile name="Apps.xml">
  <directory>/home/<account>/Werk/Divers/Prolog/XMLdata/</directory>
  <field>apl_id</field>
  <field>dns_id</field>
  <field>apl_naam_kort</field>
</factFile>

<factFile name="Dienst.xml">
  <directory>/home/<account>/Werk/Divers/Prolog/XMLdata/</directory>
  <field>dns_id</field>
  <field>dns_afkorting</field>
  <field>dns_naam</field>
</factFile>

每个 factFile 由 MySQL 创建(mysql -u username -p -X -e 'use schema; select-statement' > Apps.xml)

事实文件的数量可以改变,字段的数量也是如此。我想要的是将每个数据文件的内容(值)转换为事实。所以

<row>
  <field name="apl_id">1</field>
  <field name="dns_id">7</field>
  <field name="apl_naam_kort">Risk</field>
</row>

应转换为

assertz(apps(1, 7, Risk)).

实现这一点的最佳方法是什么?

4

1 回答 1

1

由于每行的字段数可能会发生变化并且您使用的是 SWI-Prolog,因此我相信使用record(Wielemaker & O'Keefe)是一个很好的方法。它允许指定谓词参数的子集并执行类型检查,尽早发现一些潜在的错误。

由于我在这里不知道您的 XML 架构,因此我指定了 3 个示例字段参数:

  1. apl_id的类型integer
  2. dns_id具有默认值0和非负整数类型(即nonneg)。
  3. 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价值。

以上代码可能的改进:

  1. 将价值转换集成到库record中。
  2. 除了谓词表示法(即, )之外,还允许record以对表示法(即,Name-Value或)指定库中的字段。这允许我们省略代码行。Name=ValueName(Value)NVPair =.. [Name,Value2]
  3. 可以动态更新record/1声明。如果字段名称集非常大、事先不知道和/或随时间变化,则可能需要这样做。
  4. 如果给出了使用 XML 模式数据类型 (XSD) 的 XML 模式,则可以自动导出值转换,例如xsd:nonNegativeInteger-> nonneg
于 2014-10-17T01:24:52.040 回答