株式会社エス・スリー・フォー

Xercesではやれませんか?

iPEXはインフォテリアが開発した国産XMLパーサで、開発バージョンは無償で提供されています。が、iPEXを使ったアプリケーションの再販ライセンスは有償で、それもかなりお高い…

フリーのXMLパーサ:Xerces C++を提供するApache(http://xml.apache.org/)はXMLパーサのC++実装では定評があり、Xerces C++との相性抜群なXSLプロセッサXalan C++ 1.2を使って書き直してみました。

/*
 * read_schema
 *
 *  by the use of:
 *    - Rogue Wave : SourcePro DB 4.2
 *    - Apache     : Xerces 1.5.1 & Xalan 1.2
 *
 *  build type : 'm'  -- native-StdLib / multithread / shared / release
 *               'md' -- native-StdLib / multithread / shared / debug
 */

#ifdef _MSC_VER
#pragma warning( disable: 4251 4786 )
#endif

// stdlib
#include <iostream>
#include <locale>
#include <sstream>

// Rogue Wave SourcePro DB
#define RW_DISABLE_DEPRECATED 
#include <rw/db/dbmgr.h>  // RWDBManager
#include <rw/db/dbase.h>  // RWDBDatabase
#include <rw/db/schema.h> // RWDBSchema
#include <rw/db/table.h>  // RWDBTable
#include <rw/db/reader.h> // RWDBReader
#include <rw/db/row.h>    // RWDBRow

// Xerces
#include <util/PlatformUtils.hpp>
#include <dom/DOM.hpp>
#include <parsers/DOMParser.hpp>

// Xalan
#include <XalanTransformer/XalanTransformer.hpp>
#include <XSLT/XSLTResultTarget.hpp>

/*
 * access-lib の設定。(ここでは MS SQL Server)
 */
#ifdef RWDEBUG
#define SERVER "msq42-md.dll"
#else
#define SERVER "msq42-m.dll"
#endif

// DOMString(Unicode) -> RWCString(Multibyte)
inline RWCString narrow(const DOMString& str) {
  return RWWString(str.rawBuffer(), str.length()).toMultiByte();
}

/*
 * main routine
 */
int main(int argc, char* argv[]) {

  // localeを'日本語'に設定
  std::locale::global(std::locale("japanese"));

  // Xerces / Xalan の初期化
  XMLPlatformUtils::Initialize();
  XalanTransformer::initialize();

  // XMLをパース
  DOMParser parser;
  parser.parse(argv[1]);

  // ルート・エレメント(schema)を取得
  DOM_Element schema = parser.getDocument().getDocumentElement();

  // データベースに接続
  RWCString dsn = narrow(schema.getAttribute("dsn"));
  RWCString usr = narrow(schema.getAttribute("usr"));
  RWCString pwd = narrow(schema.getAttribute("pwd"));
  RWCString db  = narrow(schema.getAttribute("db"));
  RWDBDatabase database = RWDBManager::database(SERVER, dsn, usr, pwd, db);
  if ( database.isValid() ) {
    std::cerr << database.version() << std::endl;
  } else {
    std::cerr << "can't connect to a database...¥n";
    return 1;
  }

  const char* valueType [] = {
    "NoType",       "Char",    "UnsignedChar",  "Tiny",
    "UnsignedTiny", "Short",   "UnsignedShort", "Int",
    "UnsignedInt",  "Long",    "UnsignedLong",  "Float",
    "Double",       "Decimal", "Date",          "DateTime",
    "Duration",     "String",  "Blob",          "WString"
    "MBString"
  };

  RWDBConnection connection = database.connection();

  // データベース内の全テーブルを取得
  RWDBTable  dbtables = database.dbTables(connection, RWDBDatabase::UserTable);

  std::stringstream xml;
  xml.imbue(std::locale::classic());

  // <schema dsn=... ></schema>
  xml << "<schema dsn='" << dsn << "' usr='" << usr << "' pwd='" << pwd << "' db='" << db << "'>¥n";

  // 各テーブルに対し...
  for ( RWDBReader dbreader = dbtables.reader(); dbreader(); ) {
    RWDBRow dbrow;
    dbreader >> dbrow;

    // スキーマの読み出し
    RWDBTable dbtable = database.table(dbrow[0].asString());
    dbtable.fetchSchema(connection);
    RWDBSchema dbschema = dbtable.schema();

    // <table name="テーブル名">...</table>
    xml << "  <table name='" << dbrow[0].asString() << "'>¥n";

    // スキーマの各カラムに対し...
    for ( size_t i = 0; i < dbschema.entries(); ++i ) {
      RWDBColumn dbcolumn = dbschema.column(i);

      // <column name="カラム名" 属性名="属性値" ... />
      xml << "    <column name='" << dbcolumn.name() << "' ";

      if ( dbcolumn.type() != RWDBValue::NoType )      // type
        xml << "type='" << valueType[dbcolumn.type()] << "' ";
      if ( dbcolumn.storageLength() != RWDB_NO_TRAIT ) // size
        xml << "size='" << dbcolumn.storageLength() << "' ";
      if ( dbcolumn.precision() != RWDB_NO_TRAIT )     // precision
        xml << "precision='" << dbcolumn.precision() << "' ";
      if ( dbcolumn.scale() != RWDB_NO_TRAIT )         // scale
        xml << "scale ='" << dbcolumn.scale() << "' ";
      xml << "/>¥n";
    }
    xml << "  </table>¥n";
  }
  xml << "</schema>¥n";

  if ( argc > 2 ) {
    // スタイルシート(XSL)
    XSLTInputSource xsl(argv[2]);
    // 標準出力を出力先に設定
    XSLTResultTarget out(std::cout);
    // XSLによるtransform   
    XalanTransformer transformer;
    transformer.transform(&xml,xsl,out);
  } else {
    std::cout << xml.str() << std::flush;
  }
  // 後始末
  XalanTransformer::terminate();
  XMLPlatformUtils::Terminate();

  return 0;
}