将XML数据转换为事实

时间:2014-10-15 13:32:01

标签: xpath swi-prolog fact

我的配置文件的一部分如下:

<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'使用schema; select-statement'&gt; Apps.xml)

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

<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)).

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

1 个答案:

答案 0 :(得分:1)

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

由于我不知道您的XML Schema,我已经指定了3个示例字段参数:

  1. apl_id类型integer
  2. dns_id,默认值为0,类型为非负整数(即nonneg)。
  3. apl_naam_kort类型atom
  4. 使用其他字段名称扩展record/1声明很容易。必须相应地提高dynamic/1声明的范围。

    由于SWI-Prolog带有非常好的Web标准支持(明智地选择使用SWI!),从文件(即load_xml/3)加载XML DOM并匹配行和字段是很简单的使用类似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值。

    可能的改进w.r.t.上面的代码:

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