2011年10月29日土曜日

C++でSoapは、マイノリティ?

ここんところ、プラットフォームに依存しない Soap ライブラリというテーマで、どハマリしてます。axis2 の wsdl2c では、xsd ファイル中の、abstract が処理できませんでした。GML の Filter も曲者でして、abstract な choise で4つのタイプに派生して、それぞれが、また、abstract で複雑に派生していきます。中には BinaryOp, UnaryOp とかもあって、SentenceStatement(文)とExpression(式)までXMLで表現しているので、人手でコードを補完して書くレベルを超えてます。あわよくばパッチを当ててやろうか?と思って、SchemaCompiler.java を読んでみたもののパッと修正できる代物では無さそうでした。C++ のコードは、XSLT を使って処理しているようでしたが、xsd:include を使ってないので、ごった煮でコードが読みにくい。
 で、まともに処理できたのは、gSOAP でした。SOAP Toolkit を使って ISAPI Extension を記述し、mod_isapi を利用するという手もあるとは思いますが…。
 はたと、思い出したように akaxsio2 引っ張り出してみたんですが、コンパイル通りませんでした。strcpy とか使っている部分は、string.h を include する。アドレス計算している部分は、int から stddef.h の ptrdiff_t に変える。unsigned int でなく size_t を使うといったあたりまでは、パッチを当てれそうでしたが、mutable output_file& の部分が、ちょっと厳しくて挫折しました。const output_file& に変えて、const_cast 使えば、なんとかなるかも…。でも gml のスキーマを通すのは、並大抵の事ではなく、akaxiso2 も通さなかったような記憶があります。akaxiso もちょろちょろソースを見たのですが、相当な大作です…。今なら、fusion とか使って、もっとクールに表現できそうな気もするけど、xml ライブラリは、しんどいですわ。
 お前、OpenSoap にパッチ当ててたやん?どないしてん?と思っている方もいるかもしれないので、触れておくと、ComplexType と array がサポートされていないので、使えませんでした。

放射能の航空測量の結果感想

 10月に入って、東京も含めて航空測量の結果が公表されているようである。久しぶりにデータを見てみたが、その感想を述べてみようと思う。静観すると書いておいて、何故言及するか?というと、ヒステリック過ぎる人が多いからで、書いておいた方がいいかなと思ったからである。現在はセシウムの分布もだいぶ落ちてきており、福島を中心とした一部が高いだけである。日本の気候は雨が多いので、だいぶ流れたのではないかと思う。
 また、除染の効果なのか、野菜のベクレル数も下がってきているので、3~6月ほど気にする事も無くなってきたように思う。魚に関しては、引き続き注視したいが、全体としては、良い方向に流れているのではないだろうか?
 東京などは、トンデルの論文でも有意な結果かどうかわからない程度の量である事がわかる。
 今頃になって、大騒ぎしているが、正直、反応が遅すぎるだろうと思う。もう線量は落ちてきていて、外部からちょろっと被曝する分には、どうって事は無いと思う。そういう意味では、つくづく事故直後の対応が残念でならない。SPEEDIの結果を有効活用できたはずである。発表してたとしても、せいぜい「痛いニュース」で大騒ぎされたぐらいで、日本ではパニックになる事は無かっただろうに…。
 尚、汚染の高い地域に関して、安全と言えるのかどうかについては、また別問題である。これについては、引き続き静観しようと思います。

2011年10月26日水曜日

XMLのschemaに日本語の要素名は、いい迷惑 on apache axis2c

正常な前処理トークンとなりませんの続き
要素名が日本語になっている部分を修正し、文法上エラーにならないようにして、wsdl2c で生成したソースファイルの中で、axis2_extension_mapper.c に対して、マッピングの修正をかける事にします。自動生成なので、コピペ・コーディングの変数名に修正をかけるのは、ちょっとしんどいので、boost preprocessor の出番です。

        /**
         * axis2_extension_mapper.c
         *
         * This file was auto-generated from WSDL
         * by the Apache Axis2/Java version: 1.6.1  Built on : Aug 31, 2011 (12:23:23 CEST)
         */

        #include "axis2_extension_mapper.h"

        #include "adb_foo_type0.h"
        #include "adb_foo_type1.h"
        #include "adb_Bar.h"
        
        // ここ
        #include <boost/preprocessor.hpp>
        #include <boost/preprocessor/cat.hpp>
        #include <boost/preprocessor/seq/for_each.hpp>
        #include <boost/preprocessor/tuple/elem.hpp>
        #include <boost/preprocessor/stringize.hpp>

#define TYPE_LIST \
(("要素名に","adb_要素名に",foo_type0))\
(("日本語を","adb_日本語を",foo_type1))\
(("使うなゴラー","adb_使うなゴラー",bar))

#define ADB_CREATE_MACRO(r,data,elem)  \
   if(0 == axutil_strcmp(type, BOOST_PP_TUPLE_ELEM(3,0,elem))) { \
       return (adb_type_t*) BOOST_PP_CAT(adb_,BOOST_PP_CAT(BOOST_PP_TUPLE_ELEM(3,2,elem),_create(env))); \
   }

#define ADB_CREATE_DEFAULT_MACRO(r,data,elem) \
   if(0 == axutil_strcmp(default_type, BOOST_PP_TUPLE_ELEM(3,0,elem))) { \
       return (adb_type_t*) BOOST_PP_CAT(adb_,BOOST_PP_CAT(BOOST_PP_TUPLE_ELEM(3,2,elem),_create(env))); \
   }

#define ADB_FREE_MACRO(r,data,elem) \
   if(0 == axutil_strcmp(adb_type_get_type(_object), BOOST_PP_TUPLE_ELEM(3,1,elem))) { \
       return BOOST_PP_CAT(adb_,BOOST_PP_CAT(BOOST_PP_TUPLE_ELEM(3,2,elem),_free_obj))( \
              (BOOST_PP_CAT(adb_,BOOST_PP_CAT(BOOST_PP_TUPLE_ELEM(3,2,elem),_t))*) _object, env); \
   }

#define ADB_FREE_DEFAULT_MACRO(r,data,elem) \
   if(0 == axutil_strcmp(default_type, BOOST_PP_TUPLE_ELEM(3,1,elem))) { \
       return BOOST_PP_CAT(adb_,BOOST_PP_CAT(BOOST_PP_TUPLE_ELEM(3,2,elem),_free_obj))( \
              (BOOST_PP_CAT(adb_,BOOST_PP_CAT(BOOST_PP_TUPLE_ELEM(3,2,elem),_t))*) _object, env); \
   }

#define ADB_DESERIALIZE_MACRO(r,data,elem) \
   if(0 == axutil_strcmp(adb_type_get_type(_object), BOOST_PP_TUPLE_ELEM(3,1,elem))) { \
       return BOOST_PP_CAT(adb_,BOOST_PP_CAT(BOOST_PP_TUPLE_ELEM(3,2,elem),_deserialize_obj))( \
              (BOOST_PP_CAT(adb_,BOOST_PP_CAT(BOOST_PP_TUPLE_ELEM(3,2,elem),_t))*) _object, env, dp_parent, dp_is_early_node_valid, dont_care_minoccurs); \
   }

#define ADB_DESERIALIZE_DEFAULT_MACRO(r,data,elem) \
   if(0 == axutil_strcmp(default_type, BOOST_PP_TUPLE_ELEM(3,1,elem))) { \
       return BOOST_PP_CAT(adb_,BOOST_PP_CAT(BOOST_PP_TUPLE_ELEM(3,2,elem),_deserialize_obj))( \
              (BOOST_PP_CAT(adb_,BOOST_PP_CAT(BOOST_PP_TUPLE_ELEM(3,2,elem),_t))*) _object, env, dp_parent, dp_is_early_node_valid, dont_care_minoccurs); \
   }

#define ADB_SERIALIZE_MACRO(r,data,elem) \
   if(0 == axutil_strcmp(adb_type_get_type(_object), BOOST_PP_TUPLE_ELEM(3,1,elem))) { \
       return BOOST_PP_CAT(adb_,BOOST_PP_CAT(BOOST_PP_TUPLE_ELEM(3,2,elem),_serialize_obj))( \
              (BOOST_PP_CAT(adb_,BOOST_PP_CAT(BOOST_PP_TUPLE_ELEM(3,2,elem),_t))*) _object, env, om_node, om_element, tag_closed, namespaces, next_ns_index); \
   }

#define ADB_SERIALIZE_DEFAULT_MACRO(r,data,elem) \
   if(0 == axutil_strcmp(default_type, BOOST_PP_TUPLE_ELEM(3,1,elem))) { \
       return BOOST_PP_CAT(adb_,BOOST_PP_CAT(BOOST_PP_TUPLE_ELEM(3,2,elem),_serialize_obj))( \
              (BOOST_PP_CAT(adb_,BOOST_PP_CAT(BOOST_PP_TUPLE_ELEM(3,2,elem),_t))*) _object, env, om_node, om_element, tag_closed, namespaces, next_ns_index); \
   }

        struct adb_type
        {
            axis2_char_t *property_Type;
        };

        /**
         * Auxiliary function to determine an ADB object type from its Axiom node.
         * @param env pointer to environment struct
         * @param node double pointer to the parent node to deserialize
         * @return type name on success, else NULL
         */
        axis2_char_t *AXIS2_CALL
        axis2_extension_mapper_type_from_node(
            const axutil_env_t *env,
            axiom_node_t** node)
        {
            axiom_node_t *parent = *node;
            axutil_qname_t *element_qname = NULL;
            axiom_element_t *element = NULL;

            axutil_hash_index_t *hi;
            void *val;
            axiom_attribute_t *type_attr;
            axutil_hash_t *ht;
            axis2_char_t *temp;
            axis2_char_t *type;

            while(parent && axiom_node_get_node_type(parent, env) != AXIOM_ELEMENT)
            {
                parent = axiom_node_get_next_sibling(parent, env);
            }

            if (NULL == parent)
            {
                /* This should be checked before everything */
                AXIS2_LOG_ERROR(env->log, AXIS2_LOG_SI,
                            "Failed in building adb object : "
                            "NULL elemenet can not be passed to deserialize");
                return AXIS2_FAILURE;
            }

            element = (axiom_element_t *)axiom_node_get_data_element(parent, env);

            ht = axiom_element_get_all_attributes(element, env);

            if (ht == NULL)
                return NULL;

            for (hi = axutil_hash_first(ht, env); hi; hi = axutil_hash_next(env, hi)) {
                axis2_char_t *localpart;
                axutil_hash_this(hi, NULL, NULL, &val);
                type_attr = (axiom_attribute_t *)val;
                localpart = axutil_qname_get_localpart(axiom_attribute_get_qname(type_attr, env), env);
                if (axutil_strcmp(localpart, "type") == 0) break;
            }

            type = axiom_attribute_get_value(type_attr, env);
            if (type != NULL && (temp = axutil_strchr(type, ':')) != NULL)
            {
                if (axutil_strchr(temp, ':') != NULL)
                    type = temp + 1; /* Pointer arithmetic */
            }

            return type;
        }

        axis2_char_t* AXIS2_CALL
        adb_type_get_type(const adb_type_t *object)
        {
            if (object != NULL)
              return object->property_Type;

            return NULL;
        }

        adb_type_t* AXIS2_CALL
        axis2_extension_mapper_create_from_node(
            const axutil_env_t *env,
            axiom_node_t** node,
            axis2_char_t *default_type)
        {
            axis2_char_t *type = axis2_extension_mapper_type_from_node(env, node);

            if (type != NULL)
            {
              // ここ
              BOOST_PP_SEQ_FOR_EACH(ADB_CREATE_MACRO, _, TYPE_LIST)
            }
            // ここ
            BOOST_PP_SEQ_FOR_EACH(ADB_CREATE_DEFAULT_MACRO, _, TYPE_LIST)

            return NULL;
        }

        axis2_status_t AXIS2_CALL
        axis2_extension_mapper_free(
            adb_type_t* _object,
            const axutil_env_t *env,
            axis2_char_t *default_type)
        {
            if (_object != NULL && adb_type_get_type(_object) != NULL)
            {
              // ここ
              BOOST_PP_SEQ_FOR_EACH(ADB_FREE_MACRO, _, TYPE_LIST)
            }
            // ここ
            BOOST_PP_SEQ_FOR_EACH(ADB_FREE_DEFAULT_MACRO, _, TYPE_LIST)

            return AXIS2_FAILURE;
        }

        axis2_status_t AXIS2_CALL
        axis2_extension_mapper_deserialize(
            adb_type_t* _object,
            const axutil_env_t *env,
            axiom_node_t** dp_parent,
            axis2_bool_t *dp_is_early_node_valid,
            axis2_bool_t dont_care_minoccurs,
            axis2_char_t *default_type)
        {
            if (_object != NULL && adb_type_get_type(_object) != NULL)
            {
                // ここ
                BOOST_PP_SEQ_FOR_EACH(ADB_DESERIALIZE_MACRO, _, TYPE_LIST)
            }
            // ここ
            BOOST_PP_SEQ_FOR_EACH(ADB_DESERIALIZE_DEFAULT_MACRO, _, TYPE_LIST)

            return AXIS2_FAILURE;
        }

        axiom_node_t* AXIS2_CALL
        axis2_extension_mapper_serialize(
            adb_type_t* _object,
            const axutil_env_t *env,
            axiom_node_t* om_node,
            axiom_element_t *om_element,
            int tag_closed,
            axutil_hash_t *namespaces,
            int *next_ns_index,
            axis2_char_t *default_type)
        {
            if (_object != NULL && adb_type_get_type(_object) != NULL)
            {
                // ここ
                BOOST_PP_SEQ_FOR_EACH(ADB_SERIALIZE_MACRO, _, TYPE_LIST) 
            }
            // ここ
            BOOST_PP_SEQ_FOR_EACH(ADB_SERIALIZE_DEFAULT_MACRO, _, TYPE_LIST) 

            return AXIS2_FAILURE;
        }
    

こういうのって、精神的に消耗しますね…

正常な前処理トークンとなりません

XML のスキーマ定義ファイルの要素名に日本語を使うやつがいて、そのおかげで、apache axis2 を使って、wsdlファイルからcソースを自動生成したのだが、ファイル名と変数名が日本語で出力されてしまった。ぬぉーーーっ、設計したやつ何考えとんじゃーと怒りながら、対策を考えた末、boost preprocessor で対処するのが一番だろうとテストしてみたが、一筋縄ではない。こういう設計した人に限って、別にXMLの仕様には反していませんよね?とか言いそうな気がして、ひとり、ぼやきまくっていた…。
 どこで詰まってるんやろ?と追試していると、どうやらマクロ展開する過程で、1回処理した直後に、規格通りかどうかのチェックが入っているからと推察する。
#include <boost/preprocessor/cat.hpp>
#include <boost/preprocessor/tuple/elem.hpp>
#include <boost/preprocessor/seq/for_each.hpp>
#include <boost/preprocessor/stringize.hpp>

#define TYPE_LIST \
((システム,1))\
((x,2))\
((y,4))\
((z,3))

#define MACRO(r, data, elem) BOOST_PP_STRINGIZE(BOOST_PP_CAT(BOOST_PP_CAT(BOOST_PP_TUPLE_ELEM(2,0,elem), _hoge_),BOOST_PP_TUPLE_ELEM(2,1,elem)))

BOOST_PP_SEQ_FOR_EACH(MACRO, _, TYPE_LIST)

x.cpp:14:1: エラー: "�" と "_hoge_" を貼付けましたが正常な前処理トークンとなりません

 こいつを避けるためには、日本語部分は最初から文字列リテラルとして記述しておく必要がありそうだ。幸い、日本語部分の表現は、1種類につき2通りしかないので、BOOST_PP_TUPLE_ELEM で対処しても、そんなにしんどくなさそうだ。
UTF-8 が標準ならば…と、ちょっと考えてしまう一幕でした。

2011年10月22日土曜日

いろいろ

 iTunes の環境を Windows から MacBook に変更しました。家での環境は、まじめに MacBook をメインにしようと思っています。Scansnap は、mac バージョンを間違って買ったのですが、心のどこかで確信的間違えたのではないか?と思うようになりました。

本日は、「大震災の後で人生について語るということ」と「日本の未来について話そう」の2冊を購入した。G+の方で紹介してもらった「虐殺器官」も、ちょい前にゲットした。どうでもいい事ですが、Web+DB 本屋に置いてなくて、がっくし...

ギリシャの暴動を見ていると、「ないものねだり論者」というのは、世界的な潮流なのではないか?と、同意したくなってきました。違和感を感じている部分と、同意したい部分と2通りあります。日本の震災の放射能に関する考え方の分断では、2通りの人間がいるという事なのかもしれないです。他人を心配する事で、安全とする人たちへの態度を硬化させるグループと、単純に文句を言うだけのグループです。前者の中にも、好きになれない例外の人はいますけど...。隣人への愛という点では、前者のグループも、そこからスタートしているので、そこを見間違えてはいけないと思います。それだけです。
隣国の韓国も、なかなかのものです。韓国の現状を見ていると、グローバル競争の元に、やりたいようにやったらLG電子やサムスンなど、市場を制覇する事ができたが、気がつけば、制覇した分だけ未曾有の借金が残っていて、LG電子は赤字転落で、液晶パネルの競争は国家的なダンピングだったのではないか?とも思えてきます。円高やべぇと騒いでたけども、実は白川総裁の考え方が正しくて、世界中の皆が間違っていたのでは?とも思えてきます。経済は雲をつかむようで、ほんと難しいです。世界経済もDQNが牛耳っていた???

カダフィ大佐の死体の写真を見ていて、スマートフォンに取り囲まれている様子が象徴的だと感じました。皆さんは、いかがでしょうか?拡散するのは、いいけれど、せめて、ワンクッション置いた方がいいとも思います。

追記:ひとの弱みにつけ込んで、商売するような人は、カウントしていません。

2011年10月19日水曜日

XMLを処理するのに…

Windows で C++ にて XML を処理しようと思ったら、考えられそうな選択肢がいくつかあります。

  • LibXML2
  • Expat
  • MSXML
  • TinyXML
  • XMLLite
  • Xerces-C++
そこで、なるべくならプラットフォームを固定して書きたくないので、MSXML と XMLLite が候補から外れます。
LibXML2 でやろうとしたら、ICU か iconv あたりをなんとかしないといけません。正直 iconv はmsvc でコンパイルするのが困難です。libiconv for windows ありますが、vc で、すんなりコンパイルが通りません。じゃあ ICU だわさ?って、ICUを使おうとすると、icu.lib が無いとか変なリンクエラーが出て萎えてしまいます。ICU も大げさな感じがして、使うのをちょっと躊躇われるのという事情もあります。
おまえ、選り好みが激しすぎと怒られそうですが、Xerces-C++ も、なんか、あんまり好きじゃないんです。
TinyXML もいいんですけど、ちょっと考えてしまう…(こんな事ばかり書いてると、いい加減に袋叩きにあいそう)。

そうすると残されたのは、Expat って事になります。ところが、この Expat って、SJIS に対応していないんですよね…。APIで日本語対応するって事も可能なんですが、なんというか、どうもしっくり来ない。XMLの構文を解析するついでに、文字コード変換もやりましょうという思想なんで、1文字か2文字づつコード変換の処理をしなきゃならない。これ、文字コード変換ライブラリのメンテナンスも考えたら、結構大変です。SJIS に限って言えば、SJIS第一バイトの場合は2バイト処理します。なんつーか、もやもや~とするんですよねー。

で、結論は何かと言うと、そもそも wchar_t が嫌い。これに尽きるんですわ。UTF-8 は、ほんと良く出来てると思います。

結局、自分の好みでやってくと、「文字コード変換」と「expatで遊ぼ」を組み合わせて、こんな感じになってしまいました。ただ、encoding の指定が全然関係ないやん…って部分が気に入りません。


#include <iostream>
#include <string>
#include <vector>
#include <expat.h>
#include <boost/shared_ptr.hpp>
#include <boost/foreach.hpp>

#include "codepage.hpp"
#include "wconv.hpp"

class xml_node;

class xml_node {
public:
  xml_node( const XML_Char* name ) : node_name_(name) {}
public:
  std::basic_string<XML_Char>  node_name_;
  std::basic_string<XML_Char>  node_value_;
  std::vector< boost::shared_ptr<xml_node> > childs_;
};


class xml_holder {
public:
  std::vector< boost::shared_ptr<xml_node> >  stack_;
  boost::shared_ptr<xml_node>  current_;
};

void starter(void* userData, const XML_Char* name, const XML_Char* attrs[]) {
  xml_holder* holder = reinterpret_cast<xml_holder*>(userData);
  holder->stack_.push_back( holder->current_ );
  boost::shared_ptr<xml_node> element( new xml_node( name ) );
  holder->current_->childs_.push_back( element );
  holder->current_ = element;
}

void ender( void* userData, const XML_Char* name) {
  xml_holder* holder = reinterpret_cast<xml_holder*>(userData);
  holder->current_ = holder->stack_.back();
  holder->stack_.pop_back();
}

void data( void* userData, const XML_Char* s, int len ) {
  xml_holder* holder = reinterpret_cast<xml_holder*>(userData);
  holder->current_->node_value_.assign( s, s + len );
}

void trace( int depth, boost::shared_ptr<xml_node> elem ) {
  for( int i = 0; i < depth; ++i ) { std::cout << " "; }
  std::cout << elem->node_name_ << ":" << code_to_code<CP_ACP,CP_UTF8>(elem->node_value_) << std::endl;
  BOOST_FOREACH( boost::shared_ptr<xml_node> e, elem->childs_ ) {
    trace( depth+1, e );
  }
}

bool parse_xml( const std::string& xml ) {
  xml_holder holder;
  holder.current_ = boost::shared_ptr<xml_node>( new xml_node( "root" ) );
  XML_Parser  parser = XML_ParserCreate("UTF-8");
  if( !parser ) return false;
  XML_SetUserData( parser, &holder );
  XML_SetElementHandler( parser, starter, ender );
  XML_SetCharacterDataHandler( parser, data );
  int iseof = 0;
  XML_Parse( parser, xml.c_str(), xml.size(), iseof );
  XML_ParserFree( parser );
  trace( 0, holder.current_ );
  return !iseof;
}

#include <fstream>

int main(int argc, char* argv[] ) {
  if( argc != 2 ) return 1;
  std::ifstream ifs( argv[1] );
  std::string xml;
  std::string line;
  while( ifs.good() ) {
    std::getline( ifs, line );
    xml += line;
    //std::cout << line << std::endl;
  }
  //std::cout << std::endl;

  parse_xml( code_to_code<CP_UTF8,CP_ACP>(xml) );

  return 0;
}


2011年10月13日木曜日

spirit::qi raw 習作

#include <iostream>
#include <boost/spirit/include/qi.hpp>


int main() {
  std::string src = "123456789";
  int a, b, c;
  
  namespace qi = boost::spirit::qi;
  bool result = qi::phrase_parse( 
    src.begin(), src.end(), 
    qi::raw[ qi::repeat(2)[qi::digit] ]
    >> qi::raw[ qi::digit >> qi::digit ]
    >> qi::int_
    ,
    qi::ascii::space,
    a, b, c
  );

  if( result )  std::cout << a << "," << b << "," << c << std::endl;
  else std::cout << "fault" << std::endl;

  return 0;
}