SHOEISHA iD

※旧SEメンバーシップ会員の方は、同じ登録情報(メールアドレス&パスワード)でログインいただけます

DeveloperZine(デベロッパージン)- エンジニアの意思決定を支える技術情報メディア ProductZine

CodeZine編集部では、現場で活躍するデベロッパーをスターにするためのカンファレンス「Developers Summit」や、エンジニアの生きざまをブーストするためのイベント「Developers Boost」など、さまざまなカンファレンスを企画・運営しています。

特集記事

メールでデータベースを更新するココロミ
~C++での即興実装

フリーなライブラリのコンビネーション

XMLのパース

 お次は得られたXMLのパース(解析)、<word>要素の"en"/"ja"属性を抽出します。XMLパーサは定番Apache Xerces。Xercesはメモリ上の文字列をパースできるのでおあつらえ向きです。

 Apache Xercesのダウンロードページからxerces-c_3.1.1のバイナリ版をダウンロードし、include/libパスを通して…と、ここで問題が。POP3からテキストメールを取り出すと、多くの場合日本語はiso-2022-jp(いわゆるJIS)が使われています。なればこそデコードの手間を省くためXMLの文字コードも<?xml ... encoding='iso-2022-jp' ?>としたのですが、Xercesのバイナリ版ではiso-2022-jpに対応していないためにパース時にエラー(例外)となります。幸いなことにXercesをソースからビルドすればICUを文字コードの変換に使ってくれます。ICUは巷で使われているおよそありとあらゆる文字コードとUNICODEとの相互変換をやってくれる優れモノ。ICUのプロジェクトページからバイナリ版ICUをダウンロードし、ソースコード版xerces-c_3.1.1のVC++用ソリューションprojects/Win32/VC10/xerces-allを開けて、プロジェクト:XercesLibのプロパティにICUのinclude/libパスを設定して"ICU Release"をビルドすれば、Build/Win32/VC10/ICU Releaseにlibとdllが生成されます。

 Xercesはイベント駆動型のSAXパーサと木構造を構築するDOMパーサをサポートしています。今回はDOMパーサを使って<word>要素の"en"/"ja"属性値を抽出します。

extract_words.cpp
#include <iostream>
#include <fstream>
#include <locale>
#include <string>
#include <vector>
#include <tuple>
#include <iterator>
#include <algorithm>

// Xerces
#include <xercesc/util/PlatformUtils.hpp>
#include <xercesc/parsers/XercesDOMParser.hpp>
#include <xercesc/framework/MemBufInputSource.hpp>
#include <xercesc/dom/DOM.hpp>
#include <xercesc/sax/SAXException.hpp>

using namespace std;
using namespace xercesc;

typedef tuple<wstring,wstring> word_type;

template<typename InputIterator, typename OutputIterator>
OutputIterator extract_words(InputIterator first, InputIterator last, OutputIterator out) {
  while( first != last ) {
    try {
      XercesDOMParser parser;
      MemBufInputSource source(reinterpret_cast<const XMLByte*>(first->data()), first->size(), "in_memory");
      parser.parse(source);
      DOMDocument* doc = parser.getDocument();
      DOMElement* root = doc->getDocumentElement();
      // <word> 要素の "en","ja"属性値を取り出す
      DOMNodeList* words = root->getElementsByTagName(L"word");
      for ( XMLSize_t i = 0; i < words->getLength(); ++i ) {
        DOMElement* word = static_cast<DOMElement*>(words->item(i));
        *out++ = word_type(word->getAttribute(L"en"),word->getAttribute(L"ja"));
      }
    } catch ( const SAXException& ex ) {
      wcerr << ex.getMessage() << endl;
    } catch ( const XMLException& ex ) {
      wcerr << ex.getMessage() << endl;
    } catch ( const DOMException& ex ) {
      wcerr << ex.getMessage() << endl;
    }
    ++first;
  }
  return out;
}

int main() {
  locale ja("japanese");
  wcerr.imbue(ja);
  wcout.imbue(ja);
  try {
    XMLPlatformUtils::Initialize();
  } catch ( const XMLException& ex ) {
    wcerr << ex.getMessage();
    return 1;
  }

  vector<string> msgs;
  ifstream stream("fruit.xml");
  string msg;
  copy(istreambuf_iterator<char>(stream), istreambuf_iterator<char>(), back_inserter(msg));
  msgs.push_back(msg);

  vector<word_type> words;
  extract_words(begin(msgs), end(msgs), back_inserter(words));

  wcout << L"----------- I'found these words in the XMLs ------------------" << endl;
  for_each(begin(words), end(words),
           [](const word_type& word) { wcout << get<0>(word) << L',' << get<1>(word) << endl; });

  XMLPlatformUtils::Terminate();
}

次のページ
データベースに登録

この記事は参考になりましたか?

特集記事連載記事一覧

もっと読む

この記事の著者

επιστημη(エピステーメー)

C++に首まで浸かったプログラマ。Microsoft MVP, Visual C++ (2004.01~2018.06) "だった"りわんくま同盟でたまにセッションスピーカやったり中国茶淹れてにわか茶...

※プロフィールは、執筆時点、または直近の記事の寄稿時点での内容です

この記事は参考になりましたか?

この記事をシェア

CodeZine(コードジン)
https://codezine.jp/article/detail/6726 2012/08/27 14:00

イベント

CodeZine編集部では、現場で活躍するデベロッパーをスターにするためのカンファレンス「Developers Summit」や、エンジニアの生きざまをブーストするためのイベント「Developers Boost」など、さまざまなカンファレンスを企画・運営しています。

新規会員登録無料のご案内

  • ・全ての過去記事が閲覧できます
  • ・会員限定メルマガを受信できます

メールバックナンバー