サイトアイコン 演劇とかの感想文ブログ

[nim]XMLをパース(parse)する

nimを使ってXMLファイルをパースする為の日本語情報があまりないので、「xmlparser」モジュールを使ってのXMLファイルのパースについて記事にします
色々苦労しましたが、なんとか思い通りの動きができるようになりました

目次

xmlparserモジュールの仕様

以下のリンクにて説明があります(英語)
XMLParserの仕様


使用例

といっても、所詮英語…一応以下のような仕様です

xmlをロードする

import os, streams, parsexml, strutils

var filename = "something.xml"
var s = newFileStream(filename, fmRead)
if s == nil: quit("cannot open the file " & filename)
var x: XmlParser
open(x, s, filename)

XmlParserがFileStreamをオ−プンしています

ノードを読み込む

xmlparserは、nextで次のノードに移ります
ループさせて、EOFまで読み込みます
xp.kindによって処理を分岐させる形になります

  xp.next
  block mainLoop:
    while true:
      case xp.kind
      of xmlElementStart:
		echo "element Start!"
		xp.next
      of xmlElementOpen:
		echo "element Open!"
		xp.next
      of xmlEof: break # end of file reached
      of xmlError:
        echo(errorMsg(xp))
        xp.next()
      else:
        xp.next() # skip other events
 

上記の例だと、EOF(xmlEof)まで無限ループを回して、xmlEofを見つけたら、ブレイクするという流れになります

kindは、以下のようなものがあります。よく使うものから順に紹介すると以下の通り

kindの名前 内容
xmlElementStart XMLの構成要素の開始を示します(”>”までを取得  < elem >
xmlElementEnd XMLの構成要素の終了そ示す(”>”までを取得  < /elem >
xmlElementOpen XMLの構成要素の開始を示す(”>”までを取得しない  < /elem
xmlElementClose Openで取得した構成要素の”>”を取得する  >
xmlAttribute Openで取得した構成要素の中にあるアトリビュートを取得  key=”value”
xmlCharData 文字列データ  テキスト
xmlError エラーが起きたときの N/A
xmlEOF ファイルの終了 N/A

詳細は、以下の英語の説明にあるのですが、とりあえず上記さえあれば、なんとかコントロールできます

xmlElementStartとxmlElementOpenの違い

実は、最初この2つの使い方が理解できなかったのですが、基本的には以下のような違いのようです
例えば、以下のようなXMLファイルがあったとします


  
    劇団名
    
      
        公演名a<title>
        2018/01/01
        2018/01/3
      
      
        公演名b
        2018/02/01
	2018/02/28
      
     
  

この場合に、kind==xmlElementStartで得られた構成要素の名前(elementName)を抽出すると以下のように取れます

取得するソースは、以下の通り

import os, streams, parsexml, strutils

if paramCount() 

上記のソースコードで実行結果は、以下のようになります

xml
company
name
shows
title
fromdate
todate
title
fromdate
todate

見ていただくと気づきますが、showは、抽出されていません。これは、showはアトリビュート「id」を保有しているためです

アトリビュートを保有する項目は、「xmlElementOpen」で分岐する必要があります

上記のコードを以下のように修正して実行します

import os, streams, parsexml, strutils

if paramCount() 

上記のコードの実行結果は以下のとおりです

start:xml
start:company
start:name
start:shows
open:show
start:title
start:fromdate
start:todate
open:show
start:title
start:fromdate
start:todate

この通り、この「xmlElementOpen」と「xmlElementStart」を両方キャッチしないとXMLの構成要素を全て取得することができません

要素のテキストを取得するのは、kindがCharDataであるときに取得する

上記のように、要素を特定したあとは、その要素の内容を取得します

  xp.next()  #xmlparserの次へノードを動かす
  if xp.kind==xmlCharData:  #次のノードが文字列データであることを確認
    value = xp.charData #文字列であれば、値に設定する
  else:
    value = "" 

上記のコマンドの組み合わせで、取り込めるようになりました

以上 nimでXMLファイルをパースして情報を取り込むための初歩の記事でした

PSちなみに、同様の処理をRubyとnimで実装した場合の速度比較は以下

3248のXMLファイルのパース処理

Ruby:18分4秒(4320秒)

nim :13秒

という圧倒的な差。332倍のスピード!!

ま、完全に同じ処理というわけではないのですが、それにして圧倒的です

元々Rubyを使っていた私が、処理速度の向上を目指してnimという言語を使っていろいろ試しています当たり前ですが、言語の違いによる戸惑いがあります。日本語のドキュメントもあまりないこともあり、基本中の基本も含めハマったポイント(エラーメッセージ中心に)を整理しておきますSIGSEGV: Illegal storage access.「SIGSEGV: Illegal storage access.(Attempt to read from nil?)」このエラーメッセージを見て、nil値を読み込む処理をしているつもりはなかったのですが、結果としては対象変数の初期化が必要だっただけでしたエラー...
[nim]Ruby使いがnimを使いだしてハマったポイント - 演劇とかの感想文ブログ

新しい開発言語を学ぶ必要に迫られ、今流行りの言語を色々みましたが、最終的にnimをこれから色々触ってみようという結論にいたりました。情報がまだまだ少なく、あまり有名でないこの開発言語について、少しづつ情報をためていく為の最初の一歩として「何故 nimなのか」と、開発環境の構築を記事にしておきます(2018年4月現在)処理速度の速い言語を求めて完全な日曜プログラマの私は、演劇感想文リンクの更新のためのツールをRubyで開発していますRubyは、開発者の楽しさを追った言語で、書いていて楽しいし、様々な事ができます特...
[nim]高速処理言語nimのMacOSでのセットアップと開発、テスト環境構築 - 演劇とかの感想文ブログ