- PR -

DigesterによるXMLファイルのパース時のUnknownHostException

1
投稿者投稿内容
Ichiro(51)
会議室デビュー日: 2004/09/17
投稿数: 10
お住まい・勤務地: 東京
投稿日時: 2004-12-28 14:22
お世話になっております。

Digesterクラスを使用して自分でルールを設定した上で、
XMLファイルのパースを行っています。

【問題】
XMLファイルの冒頭にて下記のような記述にてWeb上のDTDファイルに
アクセスしているため、スタンドアロン(インターネットに接続しない状態)で
実行すると「UnknownHostException」が発生してしまう。

<!DOCTYPE struts-config PUBLIC
"-//Apache Software Foundation//DTD Struts Configuration 1.1//EN"
"http://jakarta.apache.org/struts/dtds/struts-config_1_1.dtd">

【知りたいこと】
上記のWeb上のDTDファイルへのアクセスを回避(もしくは省略)し、
正常にパースを行う方法

解決策をご存知の方、ご教授いただけますよう宜しくお願い致します。

ボア
ベテラン
会議室デビュー日: 2002/05/22
投稿数: 78
投稿日時: 2004-12-29 19:29
dtd は xml(やhtml) の構文チェックをするための文法を定義したものです。
上記は書いてあるとおり struts-config.xml 用の dtd ですので、
ご自分で作成された Digester の設定ファイルに記述してあるのは
おかしいことになります。

チェックしないのであれば不要ですし、ご自分で dtd を用意される
のであれば、それを指すようにすればよいのだと思います。

[ メッセージ編集済み 編集者: ボア 編集日時 2004-12-29 19:30 ]
nak2k
ベテラン
会議室デビュー日: 2003/07/17
投稿数: 86
投稿日時: 2004-12-29 21:34
Digesterは使ったことがないのですが…。

http://www.atmarkit.co.jp/fjava/rensai2/jakarta04/jakarta04.html

こちらのリスト6にあるように、 setValidating メソッドを呼び出せばいいのでは?
Ichiro(51)
会議室デビュー日: 2004/09/17
投稿数: 10
お住まい・勤務地: 東京
投稿日時: 2005-01-05 20:38
返信が遅くなり申し訳ありません。
試行錯誤の末解決いたしましたので、報告させていただきます。

【行った対処法】
Digesterクラスのregisterメソッドを用いて、指定された公開識別子に対して
ローカルのDTDファイルのURLとの読み替えを行いました。

これにより、XMLファイルでDOCTYPE宣言されたdtdファイルをWeb上ではなく
ローカルの指定したファイルを取得しに行くことが出来ました。

Strusのソースを解析してみたのですが、
ActionServletクラス内で同様の手法を用いており、
Struts.jar内のdtdファイルを参照しているようでした。

コメントいただいた方々、本当にありがとうございました。
ピンクの恐竜
常連さん
会議室デビュー日: 2005/02/01
投稿数: 42
投稿日時: 2005-02-02 18:13
こんにちは。

解決した質問をぶりかえすようで申し訳ないのですが、
現在私も同じ現象で悩んでいます。

もしよろしければ、具体的に
registerメソッドを、どのように修正したのか教えていただけないでしょうか?

私もStrutsのソースを解析してみましたが、
たぶんStrutsでは
引用:

digester.register(
"-//Apache Software Foundation//DTD Struts Configuration 1.1//EN",
"/org/apache/struts/resources/struts-config_1_1.dtd");


とやっていると思います。

registerメソッドのAPIを見ると

引用:

public void register(java.lang.String publicId,
java.lang.String dtdURL)指定された公開識別子に対して指定された DTD の URL を登録します。 parse() の最初の呼び出し前にこれを呼び出しておく必要があります。

パラメータ:
publicId - 解決される DTD の公開識別子
dtdURL - この DTD を読み込むときに使用する URL



となっています。

ただ私の場合異なるのがdtdファイルを本当にローカルで作成していることです。
即ち、xmlファイルのdtd宣言部分で、

<!DOCTYPE config SYSTEM "config.dtd">

と宣言しています。
要はregisterメソッドの一つ目の引数である「DTD の公開識別子」が存在しません。

その場合はどのようにregisterメソッドを使用したらよろしいのでしょうか?

ちなみにxmlファイルからdtd宣言部分をコメントアウトして実行すると、
ちゃんと正常に処理が終了します。


それともう一点質問があります。
自作のdtdファイルはいったいどこに配置すればよろしいのでしょうか?
Strutsのソースのようにソースフォルダ配下に配置しなければいけないのでしょうか?
それともソースフォルダとは別のクラスパスの通ったフォルダに配置していても大丈夫なのでしょうか?

ご教授よろしくお願いします。
ピンクの恐竜
常連さん
会議室デビュー日: 2005/02/01
投稿数: 42
投稿日時: 2005-02-03 15:30
自己レスです。

私も思考錯誤の末解決しましたので、
そのやり方を報告します。

同じ問題にあたった誰かの参考になれば幸いです。

見つけ出した解決策は2つあります。
まず1つ目の解決策です。
xmlファイルのdtd宣言部分を
コード:

<!DOCTYPE config SYSTEM "config.dtd">


から
コード:

<!DOCTYPE config SYSTEM "file:///C:/eclipse3/workspace/TestXmlTools/src/test/config.dtd">


に変更しました。
当然dtdファイルまでの絶対パスは各自のパスに変更してください。
このやり方はDigesterクラスのregisterメソッドを使っていません。

これですと、一応うまく読み込んでくれます。
ただし、当然と言えば当然ですがdtdファイルまでのパスが絶対パスなので、
他の環境に持っていったときに動作しなくなるためにはっきり言って
使えません。

そこで何とかして探し出したのが次の方法です。

xmlファイルのdtd宣言部分を
コード:

<!DOCTYPE config PUBLIC "test" "file:///C:/eclipse3/workspace/TestXmlTools/src/test/config.dtd">


に変更しました。

それで
Digesterクラスのregisterメソッドを
コード:

digester.register("test","src/test/config.dtd");


と設定しました。
以上です。

これで環境が変わってもちゃんと処理してくれるばずです。

なぜそのようにしたのか理由を以下に記述します。
もし私の解釈が間違っていたらご指摘ください。
また他のやり方をご存知なら教えていただければと思います。

Digesterクラスのソースに以下のような記述がありました。
コード:

if (publicId != null)
this.publicId = publicId;

// Has this system identifier been registered?
String entityURL = null;
if (publicId != null) {
entityURL = (String) entityValidator.get(publicId);
}

// Redirect the schema location to a local destination
if (schemaLocation != null && entityURL == null && systemId != null){
entityURL = (String)entityValidator.get(systemId);
}



entityValidatorとはただのMapであって、
コード:

digester.register("test","src/test/config.dtd");


と記述して
コード:

entityValidator.put("test","src/test/config.dtd");


としているだけです。

これだけを見ると
DigesterクラスのsetPublicIdメソッドを以下のように
コード:

digester.setPublicId("test");


付け加えるだけでうまく行きそうだったのですが、
全くだめでした。

org.apache.crimson.parser.Parser2クラスに以下のようなソースを見つけました。
コード:

if (peek ("PUBLIC")) {
whitespace ("F-009");
temp = parsePublicId ();
} else if (!peek ("SYSTEM"))
return null;


ここだけを見たらよくわからないと思いますが、
(他の部分を見ても私はよくわからなかったのですが・・・^^;)
意味はたぶん

dtd宣言でPUBLICを使用していないxmlファイルは、
読込時にいくらregisterメソッドを使ってdtdファイルの読込先を
ローカルに指定したところで意味がない。

だと思います。

以上のことから読み込みxmlファイルのdtd宣言部分で
PUBLICを使用したところ、うまく行きました。

以上です。
読んでいただいた皆様の参考になればと思います。

ありがとうございました。

[ メッセージ編集済み 編集者: ピンクの恐竜 編集日時 2005-02-03 15:33 ]
1

スキルアップ/キャリアアップ(JOB@IT)