- PR -

SAXParser charactorメソッドの動作について

投稿者投稿内容
n.w
大ベテラン
会議室デビュー日: 2003/07/15
投稿数: 126
お住まい・勤務地: 神奈川
投稿日時: 2005-08-24 21:00
お世話になっています。
SAXParserについて質問させてください。
以下の様なメソッドを使用し
引数strValで渡された値 <などを<に変換する処理をSAXParserのcharactor内
で行いたいのですが<データを渡すとCharctorメソッドないでは
&とlt;charactorが2度呼ばれ分割されてしまいます。(サーバ上の話?)
※ 表示上 &は大文字
コード:

private String replace(String strVal){
System.out.println("strVal : " + strVal);
String[] arybef = {"&lt;","&gt;","&amp;","&apos;","&quot;"};
String[] aryaft = {"<",">","&","\"","\'"};
for(int i=0; i<arybef.length; i++){
strVal = strVal.replaceAll(arybef[i], aryaft[i]);
}

return strVal;
}


コード:

<?xml version="1.0" encoding="Shift_JIS" ?>
<Tag1>
<Tag2 name="Hoge">
<Tag3>
<Data name="Test">&lt;あああ</Field>
</Tag3>
</Tag2>
</Tag1>


ローカルにてSAXParserを使わずreplaceメソッドを動作確認した場合は
問題なく<として
置換がかかるのですが、Charctorメソッド内に&を含む文字列を渡すと
2つの文字列をして認識されてしまいます。
調査中ではありますが、うまく情報が見つけることが
できない為質問させていただきました。

Window XP
コンパイラ WAS6
Webspher 5.1


[ メッセージ編集済み 編集者: n.w 編集日時 2005-08-24 21:02 ]

[ メッセージ編集済み 編集者: n.w 編集日時 2005-08-24 21:02 ]

[ メッセージ編集済み 編集者: n.w 編集日時 2005-08-24 21:03 ]

[ メッセージ編集済み 編集者: n.w 編集日時 2005-08-24 21:04 ]
MMX
ぬし
会議室デビュー日: 2001/10/26
投稿数: 861
投稿日時: 2005-08-24 21:49
http://www.saxproject.org/quickstart.html
Note that a SAX driver is free to chunk the character data any way it wants, so you cannot count on all of the character data content of an element arriving in a single characters event.

ContentHandlerインターフェイスのcharactersメソッドの説明に
SAX パーサは、連続する文字データを単一のチャンクとして、またはいくつかのチャンクに分割して返します。
http://www.atmarkit.co.jp/bbs/phpBB/viewtopic.php?topic=21291&forum=12

参考
http://www.saxproject.org/apidoc/org/xml/sax/EntityResolver.html

n.w
大ベテラン
会議室デビュー日: 2003/07/15
投稿数: 126
お住まい・勤務地: 神奈川
投稿日時: 2005-08-25 11:26
MMX様、ありがとうございます。
Javadocからチャンク絡みの内容は発見していたのですが、
理解までできていなかった為、教えて頂いたリンクを元に
原因がわかりました。

対策としてはJava側でなくXMLデータ内の値をCDATAで囲むという
方法で回避することができました。
スフレ
ぬし
会議室デビュー日: 2005/05/27
投稿数: 281
お住まい・勤務地: 東京
投稿日時: 2005-08-25 14:44
その対処は間違いです。CDATAセクションで囲まれている領域も分割してcharacters()が呼ばれる可能性があります。今は動いていても、パーザの内部動作が変わったら動かなくなるかもしれません。
n.w
大ベテラン
会議室デビュー日: 2003/07/15
投稿数: 126
お住まい・勤務地: 神奈川
投稿日時: 2005-08-25 15:08
引用:

パーザの内部動作が変わったら動かなくなるかもしれません。



というのは、例えば
<Data><![CDATA[&0"0>2]]></Data>
のようにした場合 データ部分に]]>が来た場合という
ことでしょうか?
調べていて、]]>が来ると確かにおかしなことになってしまっています。

当初、<など文字が着たら&lt;に置き換えcharactor内で<置き換えて
オブジェクトに格納と考えていたのですが、&が頭についてしまいNG
となり、XML側で吸収しようと思い上記問題が発生し、現状 CDATAで
]]>という文字は入力禁止にするしかないのかと思ってましたが、
一般的にはこのような場合どういう方法をとればいいのでしょうか?


スフレ
ぬし
会議室デビュー日: 2005/05/27
投稿数: 281
お住まい・勤務地: 東京
投稿日時: 2005-08-25 15:55
コード:

<Data>[CDATA[&0"0>2]]</Data>


この場合でも、例えば「&0"0」と「>2」の2回のcharacters()が呼ばれる可能性がある、ということです。「]]>」に関しては、CDATAセクションだろうが普通の文字データだろうが書けません。

ところで、元の書き込みの replace() メソッドは、XML文書に
コード:

<Data>&amp;lt;あああ</Data>


というものが含まれていることがある、ということなんでしょうか? 妙な文書ですね。


[ メッセージ編集済み 編集者: スフレ 編集日時 2005-08-25 15:56 ]
n.w
大ベテラン
会議室デビュー日: 2003/07/15
投稿数: 126
お住まい・勤務地: 神奈川
投稿日時: 2005-08-26 09:53
お世話になっています。
ご指摘のデータですが、&などが送れないのを解決する為に
クライアント側で入力された&などを特定の文字列(&lt;など)に
置き換えていた為、直接こういうデータはありません。

で、対策としてcharacterが何度も呼ばれるならと、その動きにあわせて
グローバルへ文字列格納用の変数を用意し、characterメソッドでは
ひたすらadd処理で文字列を連結させていき、endElementメソッドで
その文字列をオブジェクトに格納としました。(その際、文字列格納用変数初期化)

ただこうした場合以下のようなエラーが発生してしまっています。
データとして aaa&bbb入力
コード:

[05/08/26 9:39:56:422 JST] 1c353300 WebGroup      
E SRVE0026E: [サーブレット・エラー]-[エンティティー "bbb" の参照は
 ';' 区切り文字で終了させる必要があります。]: 
org.xml.sax.SAXParseException: エンティティー "bbb" の参照は ';' 区切り文字で
終了させる必要があります。
	at org.apache.xerces.parsers.AbstractSAXParser.parse(Unknown Source)
	at javax.xml.parsers.SAXParser.parse(Unknown Source)
	at javax.xml.parsers.SAXParser.parse(Unknown Source)
	at com.hoge.common.xml.TestXMLParser.analyzeXML(TestXMLParser.java:89)
	at com.hoge.common.xml.TestXMLAnalyze.executeXMLAnalyze(TestXMLAnalyze.java:55)
	at com.hoge.common.xml.TestRequestProcessor.processActionPerform(TestRequestProcessor.java:78)
	at org.apache.struts.action.RequestProcessor.process(RequestProcessor.java:274)
	at org.apache.struts.action.ActionServlet.process(ActionServlet.java:1482)
	at org.apache.struts.action.ActionServlet.doPost(ActionServlet.java:525)
	at javax.servlet.http.HttpServlet.service(HttpServlet.java(Compiled Code))
	at javax.servlet.http.HttpServlet.service(HttpServlet.java(Compiled Code))
	at com.ibm.ws.webcontainer.servlet.StrictServletInstance.doService(StrictServletInstance.java(Compiled Code))
	at com.ibm.ws.webcontainer.servlet.StrictLifecycleServlet._service(StrictLifecycleServlet.java(Compiled Code))
	at com.ibm.ws.webcontainer.servlet.IdleServletState.service(StrictLifecycleServlet.java(Compiled Code))
	at com.ibm.ws.webcontainer.servlet.StrictLifecycleServlet.service(StrictLifecycleServlet.java(Inlined Compiled Code))
	at com.ibm.ws.webcontainer.servlet.ServletInstance.service(ServletInstance.java(Compiled Code))
	at com.ibm.ws.webcontainer.servlet.ValidServletReferenceState.dispatch(ValidServletReferenceState.java(Compiled Code))
	at com.ibm.ws.webcontainer.servlet.ServletInstanceReference.dispatch(ServletInstanceReference.java(Inlined Compiled Code))
	at com.ibm.ws.webcontainer.webapp.WebAppRequestDispatcher.handleWebAppDispatch(WebAppRequestDispatcher.java(Compiled Code))
	at com.ibm.ws.webcontainer.webapp.WebAppRequestDispatcher.dispatch(WebAppRequestDispatcher.java(Compiled Code))
	at com.ibm.ws.webcontainer.webapp.WebAppRequestDispatcher.forward(WebAppRequestDispatcher.java(Compiled Code))
	at com.ibm.ws.webcontainer.srt.WebAppInvoker.doForward(WebAppInvoker.java:119)
	at com.ibm.ws.webcontainer.srt.WebAppInvoker.handleInvocationHook(WebAppInvoker.java:276)
	at com.ibm.ws.webcontainer.cache.invocation.CachedInvocation.handleInvocation(CachedInvocation.java:71)
	at com.ibm.ws.webcontainer.srp.ServletRequestProcessor.dispatchByURI(ServletRequestProcessor.java:182)
	at com.ibm.ws.webcontainer.oselistener.OSEListenerDispatcher.service(OSEListener.java:334)
	at com.ibm.ws.webcontainer.http.HttpConnection.handleRequest(HttpConnection.java:56)
	at com.ibm.ws.http.HttpConnection.readAndHandleRequest(HttpConnection.java(Compiled Code))
	at com.ibm.ws.http.HttpConnection.run(HttpConnection.java:439)
	at com.ibm.ws.util.ThreadPool$Worker.run(ThreadPool.java(Compiled Code))

n.w
大ベテラン
会議室デビュー日: 2003/07/15
投稿数: 126
お住まい・勤務地: 神奈川
投稿日時: 2005-08-26 10:17
追記になります。

現状こちらで調べたものをまとめてみました。

1.&なども文字が入っている場合、特定の文字列に置き換えその文字列があった場合は
置換処理をし値を取得する(&lt;などに変換、ただし&をつけてしまっている時点で
エラー)

2.XMLにてCDATAでデータを囲む → CDATA 中に ]]> が生で登場した際、CDATAの終了が
認識されずにエラー 回避策としては ]]> を ]]> にエスケープにするがあげられるが
ここで1であげた&文字のエラーにより、回避できず。

3.1.2共に行わず、 SAXParserのcharacterメソッドにて、変数へ足しこむ処理を行い
endElementで足しこんだ文字列を取得して使用する
この場合、aaa&bbbというデータは
org.xml.sax.SAXParseException: エンティティー "bbb" の参照は ';' 区切り文字で
終了させる必要があります。
とエラーとなってしまう。


以上 3つの方法を試しましたが問題解決に至りませんでした、通常SAXParserで&など文字列が
渡された場合、一般的な処理としてはどのように行うものなのでしょうか?

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