XML工房

〔作品1〕PCのフォルダツリーを表示する

~第2章~ XMLデータの生成

2005年8月号掲載記事

前回紹介した「My Documents」フォルダを例にして、これをXMLデータ化する方法を考えてみましょう。

─────────────────────────────
My Documents
└ My Music
│ └ Sample Music
│ │ └ Beethoven's Symphony No. 9 (Scherzo).wma
│ │ └ New Stories (Highway Blues).wma
│ └ Desktop.ini
└My Pictures
│ └ Sample Pictures
│ │ └ Blue hills.jpg
│ │ └ Sunset.jpg
│ │ └ Water lilies.jpg
│ │ └ Winter.jpg
│ └ Desktop.ini
└My Webs
│ └ _private
│ └ _vti_cnf
│ └ _vti_pvt
│ │ └ botinfs.cnf
│ │ └ bots.cnf
│ │ └ service.cnf
│ │ └ service.lck
│ │ └ services.cnf
│ └ images
└ Default.rdp
└ desktop.ini
─────────────────────────────

実はこのようなフォルダツリーをXML形式にすることを最初に考えたとき、各ディレクトリ名またはファイル名を要素名にする方法を考えていました。これは前述のフォルダツリーをそのままXML形式にする感じですので、直感的で分かりやすいかな、と思ったからです。

こんなイメージ(※これはXML文書ではありません)
─────────────────────────────
<My Documents>
  <My Music>
   <Sample Music>
   ・
   ・
─────────────────────────────

ところがこの方法には大きな問題があり、Windowsの多くのファイル名は、そのままではXMLの要素名になりません。たとえば「My Documents」というフォルダ名には空白が含まれており、これはXMLの要素名になりません。またXMLの名前に「'」や「(」などの記号を使用することもできません。したがってこの方法でフォルダツリーをXML形式にするには、これらの違反事項に対して一つ一つ対処する必要があります。たとえばファイル名に含まれる空白文字をアンダースコアに変換する、などです。このようなプログラムにしてしまうと、ここで紹介するプログラムとして必要以上に大きくなってしまいますのでこれ以上は触れませんが、もしも皆さんが興味を持たれたら、XMLの命名規則を実感することができますので、この方法でのプログラム作成にトライしてみると面白いと思います。

次に考えたXML形式は以下のようなものです。
要素名を必ずDir(ディレクトリの場合)またはFile(ファイルの場合)とし、各々の要素にName属性を持たせ、その属性値にディレクトリまたはファイル名をセットする。
そして各々のファイルサイズもデータ化する必要がありますので、各々の要素にSize属性を持たせ、その属性値にファイルサイズの値をセットする。

この方法で前述のフォルダツリーをXMLデータ化すると、次のようになります。

実行結果(※インデントを加えています)
─────────────────────────────
<?xml version="1.0" encoding="Shift_JIS"?>
<Dir Name="My Documents" Size="0">
  <File Name="Default.rdp" Size="1176"/>
  <File Name="desktop.ini" Size="0"/>
  <Dir Name="My Music" Size="0">
   <File Name="Desktop.ini" Size="108"/>
   <Dir Name="Sample Music" Size="0">
    <File Name="Beethoven's Symphony No. 9 (Scherzo).wma" Size="613638"/>
    <File Name="New Stories (Highway Blues).wma" Size="760748"/>
   </Dir>
  </Dir>
  <Dir Name="My Pictures" Size="0">
   <File Name="Desktop.ini" Size="107"/>
   <Dir Name="Sample Pictures" Size="0">
     <File Name="Blue hills.jpg" Size="28521"/>
     <File Name="Sunset.jpg" Size="71189"/>
     <File Name="Water lilies.jpg" Size="83794"/>
     <File Name="Winter.jpg" Size="105542"/>
   </Dir>
   </Dir>
   <Dir Name="My Webs" Size="0">
    <Dir Name="images" Size="0"/>
    <Dir Name="_private" Size="0"/>
    <Dir Name="_vti_cnf" Size="0"/>
    <Dir Name="_vti_pvt" Size="0">
     <File Name="botinfs.cnf" Size="146"/>
     <File Name="bots.cnf" Size="323"/>
     <File Name="service.cnf" Size="1072"/>
     <File Name="service.lck" Size="0"/>
     <File Name="services.cnf" Size="3"/>
    </Dir>
   </Dir>
</Dir>
─────────────────────────────

それでは今回の最後に、これを処理するプログラムを紹介します。プログラムの動作確認はJ2SE 5で行っています。

Javaファイルのコンパイル後、実行時の引数を無しとしてプログラムを実行させると、Javaプログラムの実行カレントディレクトリを処理対象としたXMLを作成し、「output.xml」ファイルへ出力します。
>Java Dir2XML

あるいは実行時の引数として、第1引数に処理対象ディレクトリを、第2引数に出力ファイル名を、それぞれオプションとして指定することもできます。
>Java Dir2XML "C:\Documents and Settings\user1\My Documents" "mydoc.xml"

次回はこのプログラムの内容を大まかに解説した後、XSLTスタイルシートの作成に進みます。

Dir2XML.java

─────────────────────────────
import java.io.File;
 
import javax.xml.parsers.DocumentBuilder;
import javax.xml.parsers.DocumentBuilderFactory;
import javax.xml.parsers.ParserConfigurationException;
import javax.xml.transform.Transformer;
import javax.xml.transform.TransformerConfigurationException;
import javax.xml.transform.TransformerException;
import javax.xml.transform.TransformerFactory;
import javax.xml.transform.dom.DOMSource;
import javax.xml.transform.stream.StreamResult;
 
import org.w3c.dom.Document;
import org.w3c.dom.Element;
import org.w3c.dom.Node;
 
public class Dir2XML {
 // 処理対象ディレクトリの初期値
 private static String targetPath = ".";
 // 出力ファイル名の初期値
 private static String outputFile = "output.xml";
 // XMLドキュメントオブジェクト
 private static Document xmlDocument;
 // 子要素を追加するための親ノード
 private static Node parentNode;
 // 子要素となる、新しく作成した要素ノード
 private static Element activeElement;

 /**
  * エントリポイント.
  * @param args コマンドライン引数
  */
 public static void main(String[] args) {
  // オプション指定の処理対象ディレクトリ(初期値はカレントディレクトリ)
  if (args.length > 0) {
   targetPath = args[0];
  }
  // オプション指定の出力ファイル名(初期値は"output.xml")
  if (args.length > 1) {
   outputFile = args[1];
  }
 
  File rootFile = new File(targetPath);
 
  if (rootFile.exists()) {
   makeXML();
   processFile(rootFile);
  } else {
   System.out.println("Directory not exist(" + targetPath + ")");
   System.exit(0);
  }
 
  // XMLドキュメントをファイル出力し、終了
  serializeXML();
  System.out.println("\"" + outputFile + "\"" + "に出力しました");
  }
 
 /**
  * 新しいXMLドキュメントの作成.
  */
 private static void makeXML() {
  DocumentBuilderFactory dbf = DocumentBuilderFactory.newInstance();
  DocumentBuilder db = null;
  try {
   db = dbf.newDocumentBuilder();
  } catch (ParserConfigurationException pce) {
   System.out.println("Parser Configuration Exception");
   System.exit(0);
  }
 
  // 新しいXMLドキュメントノードを取得
  xmlDocument = db.newDocument();
  // 最初の親ノードをセット
  parentNode = xmlDocument;
 }
 
 /**
  * 処理対象ファイルがディレクトリならDir要素を作成しディレクトリ内部を再起処理する.
  * 処理対象ファイルがファイルならFile要素を作成する.
  * @param someFile 処理対象ファイル
  */
 private static void processFile(File someFile) {
  File[] fileList;
  long size = someFile.length();
 
  if (someFile.isDirectory()) {
   activeElement = xmlDocument.createElement("Dir");
   activeElement.setAttribute("Name", someFile.getName());
   activeElement.setAttribute("Size", Long.toString(size));
   parentNode.appendChild(activeElement);
 
   // 親ノードを変更し、再起処理を行う
   parentNode = activeElement;
   fileList = someFile.listFiles();
   for (int i = 0; i < fileList.length; i++) {
    processFile(fileList[i]);
   }
   parentNode = parentNode.getParentNode();
 
  } else {
   activeElement = xmlDocument.createElement("File");
   activeElement.setAttribute("Name", someFile.getName());
   activeElement.setAttribute("Size", Long.toString(size));
   parentNode.appendChild(activeElement);
  }
 }
 
 /**
  * XMLドキュメントのファイル出力.
  */
  private static void serializeXML() {
   TransformerFactory tf = TransformerFactory.newInstance();
   Transformer t = null;
   try {
    t = tf.newTransformer();
   } catch (TransformerConfigurationException tce) {
    System.out.println("Transformer Configuration Exception");
    System.exit(0);
   }
 
   t.setOutputProperty("encoding", "Shift_JIS");
   t.setOutputProperty("indent", "yes");
 
   try {
    t.transform(new DOMSource(xmlDocument), new StreamResult(outputFile));
   } catch (TransformerException te) {
    System.out.println("Transformer Exception");
    System.exit(0);
   }
  }
}
─────────────────────────────

続きの第3章はこちら

「XML工房」のIndexへ戻る

ページトップへ▲

HOMEへ戻る