RubyでXML (NQXML)

重要.

Rubyインタプリタには、このページで紹介しているNQXMLではなく、REXMLが採用されました。REXMLの使い方はRubyでXML (REXML)を参照。

RubyでXML文書を読み書きしてみる。

XMLパーサーいろいろ

Rubyの標準ライブラリにはXMLパーサーは含まれていない。Rubyで使えるXMLパーサーには,次のものがある。

  • NQXML
  • XMLParserモジュール
  • xmlscan

このうち,NQXMLはpure-Rubyで,メンテナンスもされているようなので,これを使ってみる。

XML文書をスキャンする

次のようなXML文書をスキャンしてみる。

<?xml version="1.0" encoding="EUC-JP"?>
<?ruby
  class Foo
    def fn(x)
      x * 2
    end
  end
?>
<!DOCTYPE hoge>
<hoge>
  <foo atr="2" bar="&lt;">This is a pen.</foo>
  Plain. 日本語
  <!-- コメント -->
  <content xml:lang="ja">
    <![CDATA[<cdata>テスト]]>
    &lt; コンテント &#33; &#x21;
  </content>
  <br />
</hoge>
<!-- コメント -->

タグ,文字データのほか,XML宣言,文書型宣言,処理命令,CDATAセクションを含み,実体参照,文字参照も使っている。

NQXMLでXML文書を読むとき,イテレータを使う方法と,DOMを使う方法がある。まずはイテレータから。

sample-1.1.rb
  4| require 'nqxml/streamingparser'
  5| 
  6| parser = nil
  7| File.open("xmlsample.xml", "r") {|f|
  8|   parser = NQXML::StreamingParser.new(f)
  9| }
 10| i = 0
 11| parser.each {|entity|
 12|   str = entity.to_s.strip
 13|   next if entity.instance_of?(NQXML::Text) && str == ""
 14|   i += 1
 15|   print "#{i}: #{str} #<#{entity.class}>\n"
 16| }

で,実行結果。

1: <?xml version="1.0" encoding="EUC-JP"?> #<NQXML::XMLDecl>
2: <?ruby
  class Foo
    def fn(x)
      x * 2
    end
  end
?> #<NQXML::ProcessingInstruction>
3: <!DOCTYPE hoge> #<NQXML::Doctype>
4: <hoge> #<NQXML::Tag>
5: <foo bar="<" atr="2"> #<NQXML::Tag>
6: This is a pen. #<NQXML::Text>
7: </foo> #<NQXML::Tag>
8: Plain. 日本語 #<NQXML::Text>
9: <!-- コメント --> #<NQXML::Comment>
10: <content xml:lang="ja"> #<NQXML::Tag>
11: <cdata>テスト #<NQXML::Text>
12: < コンテント ! ! #<NQXML::Text>
13: </content> #<NQXML::Tag>
14: <br> #<NQXML::Tag>
15: </br> #<NQXML::Tag>
16: </hoge> #<NQXML::Tag>
17: <!-- コメント --> #<NQXML::Comment>

XML文書内で次の表の左に挙げる項目が出現したときに,右に挙げるクラスのオブジェクトがブロックに渡される。

項目クラス
文字データ,CDATAセクション,参照NQXML::Text
開始タグ,終了タグ,空要素タグNQXML::Tag
XML宣言NQXML::XMLDecl
文書型宣言NQXML::Doctype
処理命令NQXML::ProcessingInstruction
コメントNQXML::Comment

CDATAセクション,実体参照(&lt;など),文字参照(&#33;,&#x21;)は,あらかじめ展開されて文字データとして扱われる。参照は文字データに埋め込まれるが,CDATAセクションは独立したオブジェクトとなる。

属性値に含まれる参照も展開される。

空要素タグは,開始タグと終了タグに展開され,二つのオブジェクトとなる。

タグの要素名は,NQXML::Tag#nameメソッドで,属性はNQXML::Tag#attrsで取り出す。属性は,開始タグはHash(属性がないときは{}),終了タグはnilが返る。