名前空間付きのXMLをServletで…

29 views
Skip to first unread message

siahr

unread,
Aug 17, 2009, 5:05:16 AM8/17/09
to xbird-jp
はじめまして。
素晴らしいものを公開していただき、ありがとうございます。

Tomcat6.0上のServletで、XQueryを処理するプログラムを書いているのですが、ちょっと困ったことが起きておりまして、ご相談する
次第です。
解決のためのヒントだけでもいただけたら幸いです。

このようなXML文書(<record>で括られるタプルが6600件程度)を、

<records xmlns:hoge="http://www.hoge.jp/dtd">
<record hoge:id="1" id="046340" hoge:href="/aozora/sakuhin/1/">
<personid hoge:href="/aozora/sakuhin/1/personid">001234</personid>
<author hoge:href="/aozora/sakuhin/1/author">愛知 敬一</author>
<workid hoge:href="/aozora/sakuhin/1/workid">046340</workid>
<title hoge:href="/aozora/sakuhin/1/title">ファラデーの伝 電気学の泰斗</title>
<kanaknd hoge:href="/aozora/sakuhin/1/kanaknd">新字新仮名</kanaknd>
<transrator hoge:href="/aozora/sakuhin/1/transrator" />
<puncher hoge:href="/aozora/sakuhin/1/puncher">松本吉彦、松本庄八</puncher>
<proofreader hoge:href="/aozora/sakuhin/1/proofreader">小林繁雄</
proofreader>
<condition hoge:href="/aozora/sakuhin/1/condition">公開</condition>
<conditiondate hoge:href="/aozora/sakuhin/1/
conditiondate">2006-12-24</conditiondate>
<source hoge:href="/aozora/sakuhin/1/source">ファラデーの傳</source>
<publisher hoge:href="/aozora/sakuhin/1/publisher">岩波書店</publisher>
<edition hoge:href="/aozora/sakuhin/1/edition">1923(大正12)年5月15日第1版</
edition>
<proofedition hoge:href="/aozora/sakuhin/1/proofedition">1923(大正12)年5
月15日第1版</proofedition>
</record>
<record hoge:id="2" id="046511" hoge:href="/aozora/sakuhin/2/">
<personid hoge:href="/aozora/sakuhin/2/personid">001245</personid>
<author hoge:href="/aozora/sakuhin/2/author">会津 八一</author>
<workid hoge:href="/aozora/sakuhin/2/workid">046511</workid>
<title hoge:href="/aozora/sakuhin/2/title">一片の石</title>
<kanaknd hoge:href="/aozora/sakuhin/2/kanaknd">新字旧仮名</kanaknd>
<transrator hoge:href="/aozora/sakuhin/2/transrator" />
<puncher hoge:href="/aozora/sakuhin/2/puncher">門田裕志</puncher>
<proofreader hoge:href="/aozora/sakuhin/2/proofreader">仙酔ゑびす</
proofreader>
<condition hoge:href="/aozora/sakuhin/2/condition">公開</condition>
<conditiondate hoge:href="/aozora/sakuhin/2/
conditiondate">2007-01-03</conditiondate>
<source hoge:href="/aozora/sakuhin/2/source">日本の名随筆88 石</source>
<publisher hoge:href="/aozora/sakuhin/2/publisher">作品社</publisher>
<edition hoge:href="/aozora/sakuhin/2/edition">1996(平成8)年8月25日第5刷</
edition>
<proofedition hoge:href="/aozora/sakuhin/2/proofedition" />
</record>

...

</records>


以下のようなXQueryで、

declare namespace hoge="http://www.hoge.jp/dtd";
<records xmlns:hoge="http://www.hoge.jp/dtd">
{for $t in doc("data.xml")/records/record return
<record>{$t/@*}
{$t/author/text() }
{ fn:concat("《", $t/title/text() , "》") }
</record>
}
</records>

処理します。

期待される結果は、

<records xmlns:hoge="http://www.hoge.jp/dtd">
<record hoge:id="1" id="046340" hoge:href="/aozora/sakuhin/1/">愛知 敬一
《ファラデーの伝 電気学の泰斗》</record>
<record hoge:id="2" id="046511" hoge:href="/aozora/sakuhin/2/">会津 八一
《一片の石》</record>

...

</records>

というような格好で、これは正常に結果が返りますが、ブラウザのリロードボタンを素早く何回も押すと、かなりの確率で

xbird.xquery.DynamicError: Writing SAX event failed
javax.xml.stream.XMLStreamException: Prefix hoge is already bound to
http://www.hoge.jp/dtd. Trying to rebind it to is an error.
at xbird.xquery.dm.ser.StAXSerializer.wrapStaxException
(StAXSerializer.java:129)
at xbird.xquery.dm.ser.StAXSerializer.evAttribute(StAXSerializer.java:
84)
at xbird.xquery.dm.ser.Serializer.evAttribute(Serializer.java:150)
at xbird.xquery.dm.instance.DocumentTableModel.export
(DocumentTableModel.java:325)
at xbird.xquery.dm.instance.DocumentTableModel.export
(DocumentTableModel.java:268)
at xbird.xquery.dm.ser.Serializer.evNode(Serializer.java:145)
at xbird.xquery.dm.ser.Serializer.emit(Serializer.java:123)
at xbird.xquery.dm.ser.Serializer.emit(Serializer.java:98)
at xbird.xquery.expr.AbstractXQExpression.evalAsEvents
(AbstractXQExpression.java:98)
at xbird.xquery.expr.opt.PathVariable.evalAsEvents(PathVariable.java:
107)
at xbird.xquery.expr.constructor.ElementConstructor.evalAsEvents
(ElementConstructor.java:293)
at xbird.xquery.expr.flwr.FLWRExpr.evalAsEvents(FLWRExpr.java:292)
at xbird.xquery.expr.constructor.ElementConstructor.evalAsEvents
(ElementConstructor.java:293)
at xbird.xquery.XQueryProcessor.execute(XQueryProcessor.java:172)
at xbird.xquery.XQueryProcessor.execute(XQueryProcessor.java:160)
at XBird.invokeQueryPushMode(XBird.java:68)
at XBird.doGet(XBird.java:51)
at javax.servlet.http.HttpServlet.service(HttpServlet.java:617)
at javax.servlet.http.HttpServlet.service(HttpServlet.java:717)
at org.apache.catalina.core.ApplicationFilterChain.internalDoFilter
(ApplicationFilterChain.java:290)
at org.apache.catalina.core.ApplicationFilterChain.doFilter
(ApplicationFilterChain.java:206)
at org.apache.catalina.core.StandardWrapperValve.invoke
(StandardWrapperValve.java:233)
at org.apache.catalina.core.StandardContextValve.invoke
(StandardContextValve.java:191)
at org.apache.catalina.core.StandardHostValve.invoke
(StandardHostValve.java:128)
at org.apache.catalina.valves.ErrorReportValve.invoke
(ErrorReportValve.java:102)
at org.apache.catalina.core.StandardEngineValve.invoke
(StandardEngineValve.java:109)
at org.apache.catalina.connector.CoyoteAdapter.service
(CoyoteAdapter.java:286)
at org.apache.coyote.http11.Http11Processor.process
(Http11Processor.java:845)
at org.apache.coyote.http11.Http11Protocol
$Http11ConnectionHandler.process(Http11Protocol.java:583)
at org.apache.tomcat.util.net.JIoEndpoint$Worker.run(JIoEndpoint.java:
447)
at java.lang.Thread.run(Unknown Source)
Caused by: javax.xml.stream.XMLStreamException: Prefix hoge is already
bound to http://www.hoge.jp/dtd. Trying to rebind it to is an error.
at
com.sun.xml.internal.stream.writers.XMLStreamWriterImpl.writeAttribute
(Unknown Source)
at xbird.xquery.dm.ser.StAXSerializer.evAttribute(StAXSerializer.java:
82)
... 29 more

というようなことになります。

データ上に、xmlns:hoge="http://www.hoge.jp/dtd" による属性値を記述してありますが、これを外すと上記のような
エラーは返りません。

長くなりますが、以下に呼び出し側の処理を貼ります。

protected void doGet(HttpServletRequest request, HttpServletResponse
response) throws ServletException, IOException {
request.setCharacterEncoding("UTF-8");
response.setCharacterEncoding("UTF-8");
response.setContentType("text/xml");
Writer out = response.getWriter();

URI baseUri = null;
String query = "declare namespace hoge=\"http://www.hoge.jp/dtd\";
<records xmlns:hoge=\"http://www.hoge.jp/dtd\"> {for $t in doc
(\"data.xml\")/records/record return <record>{$t/@*}{$t/author/text() }
{ fn:concat(\"《\", $t/title/text() , \"》\") }</record>} </records>";
InputStream is = new ByteArrayInputStream(query.getBytes
("UTF-8"));

try {
invokeQueryPushMode(is, baseUri, out);
} catch (XQueryException e) {
e.printStackTrace();
} catch (XMLStreamException e) {
e.printStackTrace();
}

}

private void invokeQueryPushMode(InputStream input, URI baseUri,
Writer writer) throws XQueryException, XMLStreamException {
XQueryProcessor proc = new XQueryProcessor();
XQueryModule module = proc.parse(input, baseUri);
XMLOutputFactory factory = XMLOutputFactory.newInstance();
XMLStreamWriter streamWriter = factory.createXMLStreamWriter
(writer);
XQEventReceiver handler = new StAXSerializer(streamWriter);
proc.execute(module, handler);
streamWriter.flush();
}

なお、当然のことながらソースコード中のinvokeQueryPushMode()メソッドを synchronized で宣言すると、上記のよう
なエラーは発生しません。

実行環境は以下の通りです

・Windows Vista 6.0
・Java(TM) SE Runtime Environment 1.6.0_15-b03
・Apache Tomcat/6.0.18

よろしくお願いいたします。

Makoto YUI

unread,
Aug 17, 2009, 6:19:23 AM8/17/09
to xbir...@googlegroups.com
はじめまして。

siahr wrote:

> private void invokeQueryPushMode(InputStream input, URI baseUri,
> Writer writer) throws XQueryException, XMLStreamException {
> XQueryProcessor proc = new XQueryProcessor();
> XQueryModule module = proc.parse(input, baseUri);
> XMLOutputFactory factory = XMLOutputFactory.newInstance();
> XMLStreamWriter streamWriter = factory.createXMLStreamWriter
> (writer);
> XQEventReceiver handler = new StAXSerializer(streamWriter);
> proc.execute(module, handler);
> streamWriter.flush();
> }
>
> なお、当然のことながらソースコード中のinvokeQueryPushMode()メソッドを synchronized で宣言すると、上記のよう
> なエラーは発生しません。

JDKの中身までおってませんが,thread safetyの件に関しては
JDKに含まれてるライブラリの問題で非スレッドセーフの
com.sun.xml.internal.stream.writers.XMLStreamWriterImpl
が再利用されてるような気がします。

同一オブジェクトIDのstreamWriterが返ったら黒です。

StAXSerializerを使わずに,SAXSerializerを使ってみてはどうでしょう。
http://code.google.com/p/xbird/source/browse/trunk/xbird-open/main/src/java/xbird/client/InteractiveShell.java#326

油井

siahr

unread,
Aug 19, 2009, 2:26:24 AM8/19/09
to xbird-jp
油井 様

ご回答ありがとうございます。
お礼が遅くなりまして申し訳ありません。

> JDKに含まれてるライブラリの問題で非スレッドセーフの
> com.sun.xml.internal.stream.writers.XMLStreamWriterImpl
> が再利用されてるような気がします。

なるほど、Servletのような環境ではこのようなところを気をつけないといけないのですね。

> StAXSerializerを使わずに,SAXSerializerを使ってみてはどうでしょう。
教えていただいた方法で、今やってみたところ、先日のようなエラーは出なくなりました。
ありがとうございます。

ところで、SAXSerializer にしてみたところ、クエリーの返却結果が少し変わりました。

ある要素が持っている全ての属性とその値を結果に含めたかったので、ここを参考にして、
http://www.w3.org/TR/2002/WD-xmlquery-use-cases-20021115/#tree-queries-results-q2
手抜きで、
return <record>{$t/@*}...
としましたが、

<records xmlns:hoge="http://www.hoge.jp/dtd">
1046340/aozora/sakuhin/1/
<record>愛知 敬一 《ファラデーの伝 電気学の泰斗》</record>
2046511/aozora/sakuhin/2/
<record>会津 八一 《一片の石》</record>
...
</records>
というようなことになりました。

変更前は
<records xmlns:hoge="http://www.hoge.jp/dtd">
<record hoge:id="1" id="046340" hoge:href="/aozora/sakuhin/1/">愛知 敬一
《ファラデーの伝 電気学の泰斗》</record>
<record hoge:id="2" id="046511" hoge:href="/aozora/sakuhin/2/">会津 八一
《一片の石》</record>
...
</records>
と、こうでした。

しかし、なんだか今回の方が正しいような気もします。引用した典拠先はかなり古いものですので。
クエリーを書き換えます。

いずれにせよ、ありがとうございました。
また質問させていただくかもしれません。
今後とも、どうかよろしくお願いいたします。

--
平井

Makoto YUI

unread,
Aug 19, 2009, 7:50:21 AM8/19/09
to xbir...@googlegroups.com
平井様

siahr wrote:
> <records xmlns:hoge="http://www.hoge.jp/dtd">
> 1046340/aozora/sakuhin/1/
> <record>愛知 敬一 《ファラデーの伝 電気学の泰斗》</record>
> 2046511/aozora/sakuhin/2/
> <record>会津 八一 《一片の石》</record>
> ...
> </records>
> というようなことになりました。
>
> 変更前は
> <records xmlns:hoge="http://www.hoge.jp/dtd">
> <record hoge:id="1" id="046340" hoge:href="/aozora/sakuhin/1/">愛知 敬一
> 《ファラデーの伝 電気学の泰斗》</record>
> <record hoge:id="2" id="046511" hoge:href="/aozora/sakuhin/2/">会津 八一
> 《一片の石》</record>
> ...
> </records>
> と、こうでした。

バグっぽいので,私に直接xmlファイルをxqueryクエリを送って
頂けたら見てみます。

油井

siahr

unread,
Sep 11, 2009, 4:17:29 AM9/11/09
to xbird-jp
皆様

この件は、rev.782 にて修正された事を確認いたしましたのでお知らせいたします。

--
平井


Reply all
Reply to author
Forward
0 new messages