lmi
[Top][All Lists]
Advanced

[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]

[lmi] soa2xml: tool for converting SOA tables in the XML format


From: Vaclav Slavik
Subject: [lmi] soa2xml: tool for converting SOA tables in the XML format
Date: Thu, 17 May 2012 18:03:48 +0200
User-agent: Mozilla/5.0 (Macintosh; Intel Mac OS X 10.7; rv:12.0) Gecko/20120428 Thunderbird/12.0.1

Hi,

below is the promised conversion tool.

Usage: soa2xml ...list of dat files...
E.g.:  ./soa2xml qx_{ann,cso,ins}.dat

It produces a large number of *.xtable files in the current directory.
These files are named after the input file and need to be in the same
directory as they are for my patches to work. For example, a request for
table #707 from /opt/lmi/data/qx_ins.dat would be satisfied by the new
actuarial_table class by loading /opt/lmi/data/qx_ins_707.xtable.

All the files created from qx_{ann,cso,ins}.dat tables pass RELAX NG
validation against the scheme I posted.  

Compilation of the tool requires LMI sources patched with the four
patches I posted. Then:

  c++ -o soa2xml.exe soa2xml.cpp \
                     actuarial_table.cpp \
                     xml_lmi.cpp \
                     alert{,_cli}.cpp \
                     -lboost_{filesystem,system}-mt -lxmlwrapp -lncurses

(I didn't add it to the makefiles, as it's an one-off tool that won't be
included in the repository. If you'd like to have it included after all,
let me know, I'll add proper makefiles for it.)

Regards,
Vaclav


---
 soa2xml.cpp     |  180 +++++++++++++++++++++++++++++++++++++++++++++++++++++++
 soa_helpers.hpp |   87 +++++++++++++++++++++++++++
 2 files changed, 267 insertions(+)

diff --git a/soa2xml.cpp b/soa2xml.cpp
new file mode 100644
index 0000000..ed1557a
--- /dev/null
+++ b/soa2xml.cpp
@@ -0,0 +1,180 @@
+
+#include "soa_helpers.hpp"
+
+#include "actuarial_table.hpp"
+#include "value_cast.hpp"
+
+#include <xmlwrapp/attributes.h>
+#include <xmlwrapp/document.h>
+#include <xmlwrapp/node.h>
+
+#include <ios>
+#include <istream>
+
+/************************************************************************
+ misc helpers
+ ************************************************************************/
+
+template<typename T>
+inline const char *as_str(T x)
+{
+    static std::string tmp;
+    tmp = value_cast<std::string>(x);
+    return tmp.c_str();
+}
+
+
+/************************************************************************
+ conversion code
+ ************************************************************************/
+
+xml::node xml_for_aggregate_table(soa_actuarial_table const& t)
+{
+    xml::node n("aggregate");
+
+    std::vector<double> const values =
+        t.values(t.min_age(), t.max_age() - t.min_age() + 1);
+
+    for(int i = 0; i < values.size(); i++)
+        {
+        xml::node v("value", as_str(values[i]));
+        v.get_attributes().insert("age", as_str(t.min_age() + i));
+        n.insert(v);
+        }
+
+    return n;
+}
+
+xml::node xml_for_duration_table(soa_actuarial_table const& t)
+{
+    xml::node n("duration");
+
+    std::vector<double> const values =
+        t.values(t.min_age(), t.max_age() - t.min_age() + 1);
+
+    for(int i = 0; i < values.size(); i++)
+        {
+        xml::node v("value", as_str(values[i]));
+        n.insert(v);
+        }
+
+    return n;
+}
+
+xml::node xml_for_select_and_ultimate_table(soa_actuarial_table const& t)
+{
+    xml::node n("select-and-ultimate");
+
+    xml::node n_select("select");
+    xml::node n_ultimate("ultimate");
+
+    // Write the <select> portion:
+    n_select.get_attributes().insert("period", as_str(t.select_period()));
+    for(int age = t.min_age(); age <= t.max_select_age(); age++)
+        {
+            std::vector<double> data = t.values(age, t.select_period());
+            xml::node n_row("row");
+            n_row.get_attributes().insert("age", as_str(age));
+            for (int s = 0; s < t.select_period(); s++)
+                {
+                xml::node v("value", as_str(data[s]));
+                n_row.insert(v);
+                }
+
+            n_select.insert(n_row);
+        }
+
+    // Write the <ultimate> portion:
+    for(int age = t.min_age(); age <= t.max_select_age(); age++)
+        {
+        std::vector<double> data = t.values(age, t.select_period() + 1);
+        xml::node v("value", as_str(data.back()));
+        v.get_attributes().insert("age", as_str(age + t.select_period()));
+        n_ultimate.insert(v);
+        }
+    for(int age = t.max_select_age() + t.select_period() + 1; age <= 
t.max_age(); age++)
+        {
+        std::vector<double> data = t.values(age, 1);
+        xml::node v("value", as_str(data.back()));
+        v.get_attributes().insert("age", as_str(age));
+        n_ultimate.insert(v);
+        }
+
+    n.insert(n_select);
+    n.insert(n_ultimate);
+
+    return n;
+}
+
+
+void export_single_table(char const* filename, int index, char const* 
description)
+{
+    fs::path table_path(filename);
+    soa_actuarial_table table(filename, index);
+
+    std::cout
+        << table.table_type()
+        << " table #"
+        << index
+        << ":\t"
+        << description
+        << std::endl;
+
+    xml::node root("table");
+    root.insert(xml::node("description", description));
+
+    switch(table.table_type())
+        {
+        case 'A':
+            root.insert(xml_for_aggregate_table(table));
+            break;
+
+        case 'D':
+            root.insert(xml_for_duration_table(table));
+            break;
+
+        case 'S':
+            root.insert(xml_for_select_and_ultimate_table(table));
+            break;
+
+        default:
+            error(boost::format("Unknown table type '%1%'.") % 
table.table_type());
+       }
+
+    xml::document doc(root);
+
+    char xmlsuffix[64];
+    sprintf(xmlsuffix, "_%d.xtable", index);
+    std::string const xmlfile = fs::basename(table_path) + xmlsuffix;
+    doc.save_to_file(xmlfile.c_str());
+}
+
+void export_soa_file(char const* filename)
+{
+    const std::vector<soa_record_info> tables = list_soa_file_tables(filename);
+
+    for(std::vector<soa_record_info>::const_iterator i = tables.begin()
+        ;i != tables.end()
+        ;++i)
+        {
+        export_single_table(filename, i->index, i->name.c_str());
+        }
+}
+
+
+int main(int argc, char *argv[])
+{
+    try
+    {
+        for(int i = 1; i < argc; i++)
+            {
+            export_soa_file(argv[i]);
+            }
+        return 0;
+    }
+    catch ( const std::exception& e )
+    {
+        std::cerr << "Error: " << e.what() << std::endl;
+        return 1;
+    }
+}
diff --git a/soa_helpers.hpp b/soa_helpers.hpp
new file mode 100644
index 0000000..74f241f
--- /dev/null
+++ b/soa_helpers.hpp
@@ -0,0 +1,87 @@
+
+#include "actuarial_table.hpp"
+#include "miscellany.hpp"
+#include "path_utility.hpp" // fs::path inserter
+
+#include <boost/cstdint.hpp>
+#include <boost/filesystem/convenience.hpp>
+#include <boost/filesystem/fstream.hpp>
+#include <boost/filesystem/path.hpp>
+#include <boost/format.hpp>
+#include <boost/static_assert.hpp>
+
+#include <climits>   // CHAR_BIT
+
+/************************************************************************
+ misc helpers
+ ************************************************************************/
+
+inline void error(const boost::format& fmt)
+{
+    throw std::runtime_error(fmt.str());
+}
+
+
+/************************************************************************
+ SOA actuarial table format helpers
+ ************************************************************************/
+
+struct soa_record_info
+{
+    int         index;
+    std::string name;
+};
+
+std::vector<soa_record_info> list_soa_file_tables(const char *filename)
+{
+    std::vector<soa_record_info> v;
+
+    fs::path index_path(filename);
+    index_path = fs::change_extension(index_path, ".ndx");
+    fs::ifstream index_ifs(index_path, ios_in_binary());
+    if(!index_ifs)
+        {
+        error(boost::format("File '%1%' is required but could not be found.") 
% index_path);
+        }
+
+    // Index records have fixed length:
+    //   4-byte integer:     table number
+    //   50-byte char array: table name
+    //   4-byte integer:     byte offset into '.dat' file
+    // Table numbers are not necessarily consecutive or sorted.
+
+    // TODO ?? Assert endianness too? SOA tables are not portable;
+    // probably they can easily be read only on x86 hardware.
+
+    BOOST_STATIC_ASSERT(8 == CHAR_BIT);
+    BOOST_STATIC_ASSERT(4 == sizeof(int));
+    BOOST_STATIC_ASSERT(2 == sizeof(short int));
+
+    int const index_record_length(58);
+    char index_record[index_record_length] = {0};
+
+    BOOST_STATIC_ASSERT(sizeof(boost::int32_t) <= sizeof(int));
+    while(index_ifs)
+        {
+        index_ifs.read(index_record, index_record_length);
+        if(index_record_length != index_ifs.gcount())
+            {
+            if(!index_ifs)
+                break;
+            error(
+                boost::format("Table index file file '%1%': attempted to read 
%2% bytes, but got %3% bytes instead.")
+                % index_path
+                % index_record_length
+                % index_ifs
+                );
+            }
+
+        soa_record_info rec;
+        rec.index = *reinterpret_cast<boost::int32_t*>(index_record);
+        rec.name.assign(index_record + 4);
+        v.push_back(rec);
+        }
+
+    return v;
+}
+
-- 
1.7.10.2




reply via email to

[Prev in Thread] Current Thread [Next in Thread]