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;
}