2010年12月23日木曜日

[java][subversion]年末に向けてひきこもり環境構築

年末は自宅でこそこそコードを書こう、書けたらいいなと思いまして
作業環境を整えています。


1. NetBeans IDE
-------------------
NetBeansの6.9.1の全部入りを入れました。古いリリースは削除。
JavaFXのプロジェクトが開けなくなりました。
もう開く必要ないだろ?ってことだよね。了解です。


2011/1/15の後日談です。
以下の作業の後、無事にJavaFXのプロジェクトを開き起動することができました。
  1. JavaFX 1.3.1をインストール
  2. Java SE Development Kit 6u23をインストール
  3. JDKの古いリリースをアンインストール
  4. NetBeans 6.9.1をアンインストール
  5. NetBeans 6.9.1を再度インストール
2. Subversionクライアント
---------------------------
TortoiseSVNの1.6と日本語パックを入れました。


3. Subversionリポジトリ
-------------------------
フリーでリポジトリをホスティングしているところを探しました。
http://www.assembla.com/
ギットもマーキュリアルもあって2時間ぐらいテンション上がったけど、
冷静さを取り戻してSubversionで。


誕生。このブログの姉妹的なリポジトリ。
http://www.assembla.com/spaces/tomorrowscode


ではまた。

2010年11月21日日曜日

[xml][dita]OTでJavaHelpをパブリッシュして開いてみる

DITA Open ToolkitのためにJavaHelpをインストールします。

OT公式ドキュメント"Installing and upgrading DITA Open Toolkit"
(installing_map.pdf)に、JavaHelpのインストール方法がありますが、
配布元の情報が古いので、以下のようにしてください。

前提ソフトウェア
---------------------
DITA Open Toolkit 1.5.2 M7

入手とインストール
---------------------
  1. JavaHelpプロジェクトのサイトに行く。URL: https://javahelp.dev.java.net/
  2. "Download the Latest JavaHelp System Build"のセクションまでスクロールする。
  3. "To download the latest JavaHelp system build, click here."の"here"をクリックする。
  4. 今日現在では以下のリンクになっている。
    http://download.java.net/javadesktop/javahelp/javahelp2_0_05.zip
  5. zipを解凍して C:\javahelp\jh2.0 に保存する。
環境変数の設定
---------------------
環境変数JHHOMEに C:\javahelp\jh2.0 を設定する。
これは startcmd.bat に書いてもいいです。
build_dita2javahelp.xmlは環境変数JHHOMEを見て動きますから必ずやってください。

---
<target name="compile.Java.Help"
    if="env.JHHOME"
    description="Compile Java Help output">
  <!-- delete 'JavaHelpSearch' directory before compiling. -->
  <condition property="compile.dir" value="${dita.map.output.dir}">
    <isset property="old.transform"/>
  </condition>
  <condition property="compile.dir" value="${output.dir}">
    <isset property="inner.transform"/>
  </condition>
  <delete dir="${compile.dir}${file.separator}JavaHelpSearch" />
  <java jar="${env.JHHOME}${file.separator}javahelp${file.separator}bin${file.separator}jhindexer.jar"
      fork="true"
      dir="${compile.dir}">
    <arg value="." />
  </java>
</target>
---

サンプルからJavaHelpをパブリッシュ
----------------------------------
{DITA-OT}\startcmd.bat をダブルクリック。
コマンドを叩く。
> ant -f build_demo.xml samples.javahelp -v

vオプションを付けて冗長メッセージにしたので、ビルドの最後の方で
compile.Java.Helpタスクが動いたっぽい形跡がわかるはずです。
(ちなみに私の環境ではJ:ドライブです。)
---
compile.Java.Help:
   [delete] Deleting directory J:\DITA-OT1.5.2\out\samples\javahelp\JavaHelpSearch
   [delete] Deleting J:\DITA-OT1.5.2\out\samples\javahelp\JavaHelpSearch\DOCS
   [delete] Deleting J:\DITA-OT1.5.2\out\samples\javahelp\JavaHelpSearch\DOCS.TAB
   [delete] Deleting J:\DITA-OT1.5.2\out\samples\javahelp\JavaHelpSearch\OFFSETS
   [delete] Deleting J:\DITA-OT1.5.2\out\samples\javahelp\JavaHelpSearch\POSITIONS
   [delete] Deleting J:\DITA-OT1.5.2\out\samples\javahelp\JavaHelpSearch\SCHEMA
   [delete] Deleting J:\DITA-OT1.5.2\out\samples\javahelp\JavaHelpSearch\TMAP
   [delete] Deleting directory J:\DITA-OT1.5.2\out\samples\javahelp\JavaHelpSearch
     [java] Executing 'C:\Program Files\Java\jre6\bin\java.exe' with arguments:
     [java] '-jar'
     [java] 'J:\javahelp\jh2.0\javahelp\bin\jhindexer.jar'
     [java] '.'
     [java]
     [java] The ' characters around the executable and arguments are
     [java] not part of the command.
---

JavaHelpビューワーで見てみる
----------------------------
J:ドライブにすべてインストールされているものとして説明します。

1. J:\javahelp\jh2.0\demos\bin\hsviewer.jar をダブルクリック。
2. HelpSet URLにチューザーから J:\DITA-OT1.5.2\out\samples\javahelp\hierarchy_helpset.hs を選ぶ。


3. [Display]ボタンをクリック。
4. おなじみのGarage SampleがJavaHelpとなって出現するはず。




    [xml][dita]OT公式ドキュメントの最近

    DITA-OT 1.5.2 M7(2010-11-19 Released) は以下のドキュメントを含んでいます。

    • DITA Readme map
      DITA-readme.pdf
    • Ant Quick Start Guide for DITA Open Toolkit
      ant-quick-start-guide-for-ditaot.pdf
    • Developerworks articles about DITA
      DITA-articles.pdf
    • Installing and upgrading DITA Open Toolkit
      installing_map.pdf
    どこが変わったのかとても気になります。
    zipから取り出したpdfをどこかにUpしたいけど、ここはダメ。もどかしい。

      2010年11月3日水曜日

      [xml][dita]OT Plug-inのアイディア - DITA to ReleaseNote/ChangeLog Plug-in

      Release NoteとChange Logのためのspecializeと、

      それっぽい見栄えのpublish。

      でも、こういった一連て、MySQLにデータ入れて

      PHPでブラウザに返すのと何も変わらない。

      変わらないなら、やる意味がない。

      トピック指向で再利用。そこがハマらないと意味がない。

      [xml][dita]OT Plug-inのアイディア - Feed to DITA

      RSS/AtomをDITAに変換したらどうだろう。

      URLを入力。DITA source fileを出力。

      で、それを、それが、どうなったら誰がどんな状況で

      うれぴいのか。

      [xml][dita]OT Plug-inのアイディア - DITA to Wiki transform あるいはその逆も

      DITAからWiki文法(Wikiフォーマット)に変換するtranstypeを
      Plug-inとして提供するとか。

      問題は、Wikiにもいろいろあるってことだけど、自分が欲しいのは
      RedmineのWiki。

      逆も欲しくなってきた。

      Wiki to DITA transform Plug-in

      最近仕事ではWiki文法でなんでもかんでも書いているから。
      Wikiフォーマットの文書をSubversionにちまちまコミットして持っているけど、
      なんかチガウヨナ感が。。

      2010年10月26日火曜日

      [xml][dita]特殊化のアイディア - Antのドキュメンテーション

      DITA Open Toolkitの仕様を調べている。

      AntやJavaはまぁわかるので、後は英語だけだなと思っていたら、
      はい来た、特殊化。DITAの特殊化。

      何かひとつ作る気で取り組んだ方が楽しいだろう。

      Antのビルドファイル、ターゲット、タスク定義をドキュメンテーションするための
      特殊化はどうだろう。自分でも使いたいな、そのドメイン。

      さっそくやってみよう。ってほどわかっちゃいないんだが。。

      2010年6月20日日曜日

      [redmine]非公開プロジェクトのカスタムクエリのAtomのリンク

      非公開のプロジェクトが配信するFeedに認証は掛かってるのかなという疑問。大丈夫でした。掛かってました。

      http://localhost:3000/projects/{プロジェクト識別子}/issues.atom?key={非公開プロジェクトではkey=valueで認証する}&query_id=1

      1. プロジェクト識別子:プロジェクトを作成するときに入力する(そして変更できない)識別子。
      2. key:非公開プロジェクトではこのkey=valueが必要。valueはRedmineが生成する。公開プロジェクトではkey=valueを付けない。
      3. query_id:カスタムクエリを登録したときにRedmineが決定してくれる識別子。
      そんな感じ。

      2010年6月13日日曜日

      [windows][ruby][redmine]WindowsXPにRedmineをインストールします

      お題
      ----------------------------------
      Redmineをインストールします。以下は時間の都合上、設定作業をとばします。

      - Subversionまわり
      - メールまわり
      - Windowsなのでパーミッションまわり


      前提
      ----------------------------------
      rack1.0.1とsqlite3-rubyがインストールされていること。"gem list"で確認してください。


      Redmineのインストール
      ----------------------------------
      1. RubyForge Redimineに行く
         http://rubyforge.org/projects/redmine/

      2. "Redmine"の"ダウンロード"をClickする

      3. "redmine-0.9.4.zip"をダウンロードする
         http://rubyforge.org/frs/download.php/70488/redmine-0.9.4.zip

      4. "J:\redmine-0.9.4"に解凍する


      データベースへの接続の設定
      ----------------------------------
      1. SQLite3を使うのでデータベース側の準備作業は無い。

      2. "J:\redmine-0.9.4\config\database.yml.example"を"database.yml"にコピーして編集する。
      ---
      production:
        adapter: sqlite3
        dbfile: db/redmine.db
        timeout: 5000
      ---
      とりあえずproductionだけ変更する。


      セッション暗号化用鍵の生成
      ----------------------------------
      以下、コマンドプロンプトより。
      ---
      J:\redmine-0.9.4>set RAILS_ENV=production
      J:\redmine-0.9.4>rake config/initializers/session_store.rb
      (in J:/redmine-0.9.4)
      ---


      データベースの初期化
      ----------------------------------
      以下、コマンドプロンプトより。
      ---
      J:\redmine-0.9.4>set RAILS_ENV=production
      J:\redmine-0.9.4>rake db:migrate
      (in J:/redmine-0.9.4)
      ==  Setup: migrating =====================================
      -- create_table("attachments", {:force=>true})
         -> 0.0781s
      (以下略。大量のメッセージ。)
      ---

      引き続き、初期データを投入する。
      ---
      J:\redmine-0.9.4>set RAILS_ENV=production
      J:\redmine-0.9.4>rake redmine:load_default_data
      (in J:/redmine-0.9.4)

      Select language: bg, bs, ca, cs, da, de, el, en, es, fi, fr, gl, he, hr, hu, id,
       it, ja, ko, lt, nl, no, pl, pt, pt-BR, ro, ru, sk, sl, sr, sv, th, tr, uk, vi,
      zh, zh-TW [en] ja
      ====================================
      Default configuration data loaded.

      ---
      言語を選べというのでjaにした。


      動作確認
      ----------------------------------
      WEBrick webサーバを起動して動作確認する。

      1. 以下コマンドプロンプトから
      ---
      J:\redmine-0.9.4>ruby script\server webrick -e production
      => Booting WEBrick
      => Rails 2.3.5 application starting on http://0.0.0.0:3000
      ./script/../config/../vendor/rails/railties/lib/rails/gem_dependency.rb:119:Warn
      ing: Gem::Dependency#version_requirements is deprecated and will be removed on o
      r after August 2010.  Use #requirement
      ---
      警告が出ているものの先を急ぐ。

      2. ブラウザから開く。
         http://localhost:3000/ Redmineサイトが現われた!
         admin/adminでログインする。ログインできた!

      3. Ctrl + CでWEBrickを停止する。


      ではまた。

      [ruby][rack]Rack 1.0.1をインストールします

      お題
      ----------------------------------
      WindowsXP + Ruby + RubyGems がある環境にRack 1.0.1をインストールします。


      手順
      ----------------------------------
      1. Rack: a Ruby Webserver Interfaceに行く
         http://rack.rubyforge.org/

      2. "rack-1.0.1.tar.gz (Rubyforge)"をClickする。
         http://rubyforge.org/frs/download.php/65735/rack-1.0.1.tar.gz

      3. "J:\download\rack-1.0.1"に解凍する。

      4. rackのgemファイルをビルドする。
      ---
      J:\download\rack-1.0.1>gem build rack.gemspec
        Successfully built RubyGem
        Name: rack
        Version: 1.0.1
        File: rack-1.0.1.gem
      ---

      5. rackのgemファイルをインストールする。
      ---
      J:\download\rack-1.0.1>gem install -l rack-1.0.1.gem
      Successfully installed rack-1.0.1
      1 gem installed
      Installing ri documentation for rack-1.0.1...
      Installing RDoc documentation for rack-1.0.1...
      ---

      6. 確認する。
      ---
      J:\download\rack-1.0.1>gem list

      *** LOCAL GEMS ***

      rack (1.0.1)
      rake (0.8.7)
      ---

      SRPMからRPM作ってインストールする手順とそっくり。。

      ではまた。

      [sqlite3]WindowsXPにSQLite3をインストールします

      お題
      ----------------------------------
      SQLite3をインストールします




      SQLite3のインストール
      ----------------------------------
      1. SQLite Downloadサイトに行く
         http://www.sqlite.org/download.html

      2. "Precompiled Binaries For Windows"のセクションを見る

      3. "sqlite-3_6_23_1.zip"をダウンロードする
         http://www.sqlite.org/sqlite-3_6_23_1.zip

      4. "sqlitedll-3_6_23_1.zip"をダウンロードする
         http://www.sqlite.org/sqlitedll-3_6_23_1.zip

      5. 解凍する

      6. "sqlite3.dll"をPATHに加える





      sqlite3-rubyのインストール
      ----------------------------------
      1. RubyForge SQLLite-Rubyに行く
         http://rubyforge.org/projects/sqlite-ruby/

      2. "sqlite3-ruby"の"ダウンロード"をClickする

      3. "sqlite3-ruby-1.3.0-x86-mingw32.gem"をダウンロードする
         http://rubyforge.org/frs/download.php/71086/sqlite3-ruby-1.3.0-x86-mingw32.gem
         このパッケージの選択に全く自信なし。

      4. インストールする
      ---
      J:\download>gem install -l sqlite3-ruby-1.3.0-x86-mingw32.gem
      Successfully installed sqlite3-ruby-1.3.0-x86-mingw32
      1 gem installed
      Installing ri documentation for sqlite3-ruby-1.3.0-x86-mingw32.

      Enclosing class/module 'mSqlite3' for class Statement not known

      No definition for libversion
      Installing RDoc documentation for sqlite3-ruby-1.3.0-x86-mingw3

      Enclosing class/module 'mSqlite3' for class Statement not known

      No definition for libversion
      ---
      警告メッセージが出ているけど気にしないでおく。


      5.確認する。
      ---
      J:\download>gem list

      *** LOCAL GEMS ***

      rack (1.0.1)
      rake (0.8.7)
      sqlite3-ruby (1.3.0 x86-mingw32)

      ---


      ではまた。

      [ruby][rake][redmine]WindowsXPにRuby 1.8.7をインストールします

      お題
      ---------------------------
      Windows XPにRubyをインストールします。
      今回選択したRubyのバージョン1.8.xは、Redmineの要求に合わせたものです。


      ダウンロードとインストール
      ---------------------------
      1. RubyForge: Ruby Installer
         http://rubyforge.org/projects/rubyinstaller/

      2. Click Ruby Installer's "download"

      3. Click rubyinstaller-1.8.7-p249.exe
         http://rubyforge.org/frs/download.php/71067/rubyinstaller-1.8.7-p249.exe


      動作確認
      ---------------------------
      以下、コマンドプロンプトから。
      ---
      C:\Documents and Settings\takaaki>ruby -v
      ruby 1.8.7 (2010-01-10 patchlevel 249) [i386-mingw32]

      C:\Documents and Settings\takaaki>ruby -e 'print "Hello World\n"'
      Hello World
      ---

      ツール - RDoc, Ruby Gems and Rake
      ---------------------------
      RDocはjavadocに、Gemはrpmとかyumに、Rakeはantに相当するらしいです。


      以下、コマンドプロンプトから。
      ---
      C:\Documents and Settings\takaaki>rdoc --version
      RDoc V1.0.1 - 20041108

      C:\Documents and Settings\takaaki>gem -v
      1.3.7

      C:\Documents and Settings\takaaki>rake --version
      'rake' は、内部コマンドまたは外部コマンド、
      操作可能なプログラムまたはバッチ ファイルとして認識されていません。
      ---
      Rakeが入っていませんでした。1.9.1では入ったのに。。。

      Rakeのインストール
      ---------------------------
      ここではあえて"gem install rake"コマンドを使ったネット経由でのインストールをしません。
      パッケージをダウンロードして、ファイル名を指定してインストールします。


      1. RubyForge: Rake
         http://rubyforge.org/projects/rake/

      2. Click rake-0.8.7's "download"

      3. Click rake-0.8.7.gem
         http://rubyforge.org/frs/download.php/56871/rake-0.8.7.gem

      4. 確認します。以下、コマンドプロンプトから。
      ---
      C:\Documents and Settings\takaaki>gem install -l j:\download\rake-0.8.7.gem
      Successfully installed rake-0.8.7
      1 gem installed
      Installing ri documentation for rake-0.8.7...
      Installing RDoc documentation for rake-0.8.7...

      C:\Documents and Settings\takaaki>rake --version
      rake, version 0.8.7
      ---


      ではまた。

      2010年6月12日土曜日

      [ruby]Windows XPにRuby 1.9.1をインストールします



      お題
      ---------------------------
      Windows XPにRubyをインストールします。


      ダウンロードとインストール
      ---------------------------
      1. RubyForge: Ruby Installer
         http://rubyforge.org/projects/rubyinstaller/

      2. Click Ruby Installer's "download"

      3. Click rubyinstaller-1.9.1-p378.exe
         http://rubyforge.org/frs/download.php/71078/rubyinstaller-1.9.1-p378.exe

      奇数のマイナーバージョンは開発版ということになっていますが、1.9の安定版が1.9.1なのだそうです。


      動作確認
      ---------------------------
      以下、コマンドプロンプトから。
      ---
      C:\Documents and Settings\takaaki>ruby -v
      ruby 1.9.1p378 (2010-01-10 revision 26273) [i386-mingw32]

      C:\Documents and Settings\takaaki>ruby -e 'print "Hello World\n"'
      Hello World
      ---



      一緒に入るもの - GemとRake
      ---------------------------
      Gemはrpmとかyumに相当し、Rakeはmakeとかantに相当するらしいです。
      ---
      C:\Documents and Settings\takaaki>gem -v
      1.3.7

      C:\Documents and Settings\takaaki>rake --version
      rake, version 0.8.3

      ---


      ではまた。






      2010年5月5日水曜日

      [java][swing][jdialog]最初開いたサイズを最小サイズにする

      お疲れさまです。


      リサイザブルなダイアログで、最初に開いたサイズより小さくはさせない。
      でも大きくはできる。


      ---
      dialog.setMinimumSize(dialog.getSize());
      dialog.setVisible(true);
      ---


      こんな感じで。


      [java][swing][GroupLayout]男は(女も)黙ってGroupLayout

      お疲れさまです。


      NetBeansのGUIビルダはデフォルトでGroupLayoutを用意してくれます。
      (今までNullLayoutだと思い込んでました。)


      一方でGUIビルダでGroupLayoutを使うにはどうしたらいいんだろうって
      ずっとモヤモヤしてました。


      こんのバカチンがっ!orz


      いわゆるラベルの長さはまちまちだけど、テキストフィールドの位置は揃って欲しスの
      解決策は身近なところに用意されていたのです。




      いろんなレイアウトをごちゃごちゃ使った過去の実装を全部見直さないといけません。


      ではまた。

      2010年3月13日土曜日

      [java][swing][borderlayout][jsplitpane]リサイズするとこしないとこ

      お疲れ様です。


      リサイズ可能なダイアログを作ったときの、コンポーネントのレイアウトと、動かせる境界線(JSplitPane)のサンプルです。仕様はこうです。

      • ダイアログはリサイズできます。
      • JTextFieldは、ダイアログのリサイズに追従して横に広がります。縦には広がりません。
      • JTableは、ダイアログのリサイズに追従して縦にも横にも広がります。
      • JTextAreaも同様です。
      • JTableとJTextAreaの比率を、間の境界線をドラッグすることで変えることができます。
      • JButtonは常に右寄せでリサイズに追従します。もちろんボタンの大きさは変わりません。



      ではまた。

      2010年2月27日土曜日

      [java][swing][borderlayout]リサイズにコンポーネントを追従させる

      お疲れ様です。
      JDialogをリサイズさせたときに、JTextFieldのサイズも一緒にリサイズされたらいいのにと。
      下図のjLabel1とjTextField1は、JPanelに属させていて、そのレイアウトをFlowLayoutに
      した例です。これだとリサイズに追従しません。
      FlowLayoutをやめてBorderLayoutに変更します。ラベルをBorderLayout.LINE_STARTに配して、テキストフィールドをBorderLayout.CENTERに配します。こうなります。
      テキストフィールドがダイアログの幅(というかJPanelの幅)いっぱいに広がりました。
      これを幅と高さ共にリサイズしてみます。
      リサイズに追従しました。思いがけず高さまで追従しましたが、これはこれで意味がありますまずいので、後日ちゃんとします。


      ではまた。

      [java][swing][jtable]テーブルのヘッダのラベルを左寄りにする

      お疲れ様です。
      NetBeansのGUIビルダでJTableを作るとノンコーディングでこんな感じになります。




      テーブルのヘッダのラベルがセンタリングされているのがわかりますね。
      これを左寄りにするにはこうします。
      ---
      DefaultTableCellRenderer dtcr = (DefaultTableCellHeaderRenderer)jTable1.getTableHeader().getDefaultRenderer();
      dtcr.setHorizontalAlignment(SwingConstants.LEFT);
      ---
      GUIビルダで生成されるinitComponents()よりも後ろで効かせればいいです。



      はい。左に詰まりました。

      ではまた。

      2010年2月21日日曜日

      [java][io]RandomAccessFileのreadLineをUTF-8に対応させる

      オリジナルのreadLineは1バイト読み込んで1つのcharに変換し、
      最後にStringとして返しますが、そうすると日本語とか復元できません。
      これはAPIにも書いてあります。
      そこでreadLineのコードをちょこっと改造してみました。
      ---
      /**
       * <code>RandomAccessFile.read</code>で読み込んだバイト配列を
       * UTF-8エンコードした<code>String</code>で返します。
       * EOFに達するとnullを返します。
       * @param f
       * @return
       * @throws IOException
       */
      public static String readLineRandomAccessFileUTF(final RandomAccessFile f) 
        throws IOException {
        List<Byte> input = new ArrayList<Byte>();
        int c = -1;
        boolean eol = false;
        while (!eol) {
          switch (c = f.read()) {
          case -1: //EOFに達した場合
          case '\n':
            eol = true;
            break;
          case '\r':
            eol = true;
            long cur = f.getFilePointer();
            if ((f.read()) != '\n') {
              f.seek(cur);
            }
            break;
          default:
            input.add((byte)c);
            break;
          }
        }


        if ((c == -1) && (input.size() == 0)) {
          return null;
        }
        byte[] bytes = new byte[input.size()];
        for(int i=0;i<input.size();i++){
          bytes[i]=input.get(i);
        }
        return new String(bytes, "utf8");
      }
      ---
      今回はテストケース無しです。

      2010年2月14日日曜日

      [java][dom]ネストした要素をフラットに再配置する

      例えばfontタグの中にfontタグを入れないように一個ずつ閉じましょうみたいなことです。
      次の実装の例は親子関係をフラットに再配置します。ただし、矯正できるのは親子関係(二代)までです。


      ---
      /**
       * ネストした要素をフラットに再配置します。
       * 
       * 変換前
       * <phrase>We <phrase>are </phrase>the <phrase>world.</phrase></phrase>;
       * 変換後
       * <phrase>We </phrase><phrase>are </phrase><phrase>the </phrase><phrase>world.</phrase>
       * @param target
       */
      public static void flattenNestedElement(final Element target){
        if(target == null) throw new IllegalArgumentException();
        
        String targetName = target.getNodeName();
        Element parent = (Element)target.getParentNode();
        for(int i=0;i<target.getChildNodes().getLength();){
          Node child = target.getChildNodes().item(i);
          if(child.getNodeType() == Node.ELEMENT_NODE && child.getNodeName().equals(targetName)){
            parent.insertBefore(child, target);
          }else{
            Node copy = target.cloneNode(false);
            parent.insertBefore(copy, target);
            copy.appendChild(child);
          }
        }
        parent.removeChild(target);
      }
      ---

      テストケースです。
      ---
      @Test
      public void testFlattenNestedElement_DocBook4_Phrase() throws Exception{
        StringBuilder sb = new StringBuilder();
        sb.append("<section><para>");
        sb.append("<phrase revisionflag=\"changed\">基本 XML 値を");
        sb.append("<phrase revision=\"01\"><emphasis role=\"bold\">定数</emphasis>として</phrase>");
        sb.append("格納する");
        sb.append("<phrase revision=\"02\">ユーティリティー</phrase>");
        sb.append("クラスです。</phrase>");
        sb.append("</para></section>");
        String xml = sb.toString();
        
        sb.setLength(0);
        sb.append("<section><para>");
        sb.append("<phrase revisionflag=\"changed\">基本 XML 値を</phrase>");
        sb.append("<phrase revision=\"01\"><emphasis role=\"bold\">定数</emphasis>として</phrase>");
        sb.append("<phrase revisionflag=\"changed\">格納する</phrase>");
        sb.append("<phrase revision=\"02\">ユーティリティー</phrase>");
        sb.append("<phrase revisionflag=\"changed\">クラスです。</phrase>");
        sb.append("</para></section>");
        String expected = sb.toString();
        
        Document doc = DomUtils.stringToDocument(xml);
        NodeList nodeList = DomUtils.findNodesByXPath(doc, "/section/para/phrase");
        Element target = (Element)nodeList.item(0);
        DomUtils.flattenNestedElement(target);
        String actual = DomUtils.nodeToString(doc);
        actual = XMLUtils.removeXMLDeclaration(actual);
        assertEquals(expected, actual);
      }
      ---

      ではまた。

      2010年2月13日土曜日

      [java][dom]構造化されたタグの解除(2)

      もう少し多層なテストケースです。
      ---
      /**
       * 子要素を親要素に移動して自身の要素を削除することによりタグを解除できるか。
       * <p>
       * DocBook4のvariablelistの場合
       */
      @Test
      public void testPullUpChildByXPath_DocBook4_Variablelist() throws Exception{
        StringBuilder sb = new StringBuilder();
        sb.append("<section>");
        sb.append("<title>Java Platform, Standard Edition 6 API 仕様</title>");
        sb.append("<variablelist>");
        sb.append("<varlistentry>");
        sb.append("<term revisionflag=\"changed\">java.applet</term>");
        sb.append("<listitem>");
        sb.append("<para>アプレットの作成、およびアプレットとアプレットコンテキストとの通信に使用するクラスの作成に必要なクラスを提供します。</para>");
        sb.append("</listitem>");
        sb.append("</varlistentry>");
        sb.append("<varlistentry>");
        sb.append("<term>java.<phrase revisionflag=\"changed\">awt</phrase></term>");
        sb.append("<listitem>");
        sb.append("<para>ユーザーインタフェースの作成およびグラフィックスとイメージのペイント用のすべてのクラスを含みます。</para>");
        sb.append("</listitem>");
        sb.append("</varlistentry>");
        sb.append("<varlistentry>");
        sb.append("<term>java.beans</term>");
        sb.append("<listitem>");
        sb.append("<para>カラースペースのクラスを</para>");
        sb.append("<para>提供します。</para>");
        sb.append("</listitem>");
        sb.append("</varlistentry>");
        sb.append("</variablelist>");
        sb.append("</section>");
        String xml = sb.toString();
        
        sb.setLength(0);
        sb.append("<section>");
        sb.append("<title>Java Platform, Standard Edition 6 API 仕様</title>");
        sb.append("java.applet");
        sb.append("<para>アプレットの作成、およびアプレットとアプレットコンテキストとの通信に使用するクラスの作成に必要なクラスを提供します。</para>");
        sb.append("java.<phrase revisionflag=\"changed\">awt</phrase>");
        sb.append("<para>ユーザーインタフェースの作成およびグラフィックスとイメージのペイント用のすべてのクラスを含みます。</para>");
        sb.append("java.beans");
        sb.append("<para>カラースペースのクラスを</para>");
        sb.append("<para>提供します。</para>");
        sb.append("</section>");
        String expected = sb.toString();
        
        Document doc = DomUtils.stringToDocument(xml);
        //子の引き上げは下層からやります。
        DomUtils.pullUpChildByXPath(doc, "/section/variablelist/varlistentry/term");
        DomUtils.pullUpChildByXPath(doc, "/section/variablelist/varlistentry/listitem");
        DomUtils.pullUpChildByXPath(doc, "/section/variablelist/varlistentry");
        DomUtils.pullUpChildByXPath(doc, "/section/variablelist");
        String actual = DomUtils.nodeToString(doc);
        actual = XMLUtils.removeXMLDeclaration(actual);
        assertEquals(expected, actual);
      }
      ---

      ではまた。

      [java][dom]構造化されたタグの解除

      こんな感じで。
      ---
      /**
       * 子要素を親要素に移動して自身の要素を削除することによりタグを解除します。
       * @param doc
       * @param xpathExpression 削除したい要素を指定するためのXPath式
       */
      public static void pullUpChildByXPath(final Document doc, final String xpathExpression) 
        throws XPathExpressionException{
        XPathFactory factory = XPathFactory.newInstance();
        XPath xpath = factory.newXPath();
        NodeList nodes = 
          (NodeList) xpath.evaluate(xpathExpression, doc, XPathConstants.NODESET);
        for(int i=0;i<nodes.getLength();i++){
          Node node = nodes.item(i);
          if(node.getNodeType() == Node.ELEMENT_NODE){
            pullUpChild((Element)node);
          }
        }
      }
      /**
       * 子要素を親要素に移動して自身の要素を削除します。
       * @param element 削除したい要素
       */
      public static void pullUpChild(final Element element){
        //親を呼び出します。
        Node parent = element.getParentNode();
        NodeList childNodes = element.getChildNodes();  
        //ノードの挿入は親に頼みます。
        for(int j=0; j < childNodes.getLength(); j++){
          Node child = childNodes.item(j).cloneNode(true);
          parent.insertBefore(child, element);
        }
        parent.removeChild(element);
      }
      ---

      テストケースです。
      ---
      @Test
      public void testPullUpChildByXPath_DocBook4_OrderedList() throws Exception{
        StringBuilder sb = new StringBuilder();
        sb.append("<section>");
        sb.append("<title>Java Platform, Standard Edition 6 API</title>");
        sb.append("<orderedlist>");
        sb.append("<title>パッケージ</title>");
        sb.append("<listitem>");
        sb.append("<para revisionflag=\"added\">java.applet</para>");
        sb.append("</listitem>");
        sb.append("<listitem>");
        sb.append("<para>java.<phrase revisionflag=\"changed\">awt</phrase></para>");
        sb.append("</listitem>");
        sb.append("<listitem>");
        sb.append("<para>java.beans</para>");
        sb.append("<para>Beans (JavaBeans アーキテクチャーに基づいたコンポーネント) の開発に関連するクラスが含まれています。</para>");
        sb.append("</listitem>");
        sb.append("</orderedlist>");
        sb.append("</section>");
        String xml = sb.toString();
        
        sb.setLength(0);
        sb.append("<section>");
        sb.append("<title>Java Platform, Standard Edition 6 API</title>");
        sb.append("<title>パッケージ</title>");
        sb.append("<para revisionflag=\"added\">java.applet</para>");
        sb.append("<para>java.<phrase revisionflag=\"changed\">awt</phrase></para>");
        sb.append("<para>java.beans</para>");
        sb.append("<para>Beans (JavaBeans アーキテクチャーに基づいたコンポーネント) の開発に関連するクラスが含まれています。</para>");
        sb.append("</section>");
        String expected = sb.toString();
        
        Document doc = DomUtils.stringToDocument(xml);
        //子の引き上げは下層からやります。
        DomUtils.pullUpChildByXPath(doc, "/section/orderedlist/listitem");
        DomUtils.pullUpChildByXPath(doc, "/section/orderedlist");
        String actual = DomUtils.nodeToString(doc);
        actual = XMLUtils.removeXMLDeclaration(actual);
        assertEquals(expected, actual);
      }
      ---

      ではまた。