XPAGEで膨大なJSONデータをリッチテキストフィールドに保存する方法

テキストフィールドの最大サイズは32KBまで

昨今、Big DataやらCongnitive、Watsonなどで大量のデータを扱う機会が増えています。Notes/DominoでさすがにBig Dataと呼ばれる類のものを扱っているNSFにまだお目にかかったことがありませんが、それでも今後、色々な場面で今まで以上に大きなサイズのデータを扱う機会は増えてくると思います。

自分の例では今回のテーマの通り、フィールドに膨大なJSONデータを保持させたいという希望がありました。どれだけ膨大かというと1フィールドに少なくとも数百KBは保持する必要がありました。

ここでまず通常のテキストフィールドにJSONを保存を試みた場合。Notes/Dominoではテキストフィールドの最大サイズは32KBまでという制限があり、それ以上のデータを保持してくれません。
詳しくはIBM Champion御代さんの最近のブログで触れられています。とてもためになるので是非みてください。⇒ 文書サマリーデータの上限を 16 MB に増やしてみた – のおつ -Notes/Dominoに関すること-

リッチテキストフィールドには32KBの制限なし!

テキストフィールドがだめなら、次に思いつくのがリッチテキストフィールド。リッチテキストフィールドには32KBのサイズ制限がありません。正確には使用可能なディスク領域によってのみ制限されます(1GB以下)。

リッチテキストにJSONデータを保存させる

方針は決まれば、まずフォームにリッチテキストフィールドをJSON格納用に追加します。後はXPAGESでリッチテキストフィールドにJSONを格納して保存してやるだけ、、、と思いきや一筋縄ではいかない難関が待ち構えていました。

リッチテキストにJSONデータをそのまま保存させた場合の落とし穴

自分がまず試したXPAGEのコードが以下の通りです

<?xml version="1.0" encoding="UTF-8"?>
<xp:view xmlns:xp="http://www.ibm.com/xsp/core">

	<xp:this.data>
		<xp:dominoDocument var="document1" action="editDocument"
			formName="Contact" computeWithForm="both">
		</xp:dominoDocument>
	</xp:this.data>
 	
	<xp:inputRichText id="inputRichText1" value="#{document1.CanvasJson}"></xp:inputRichText>
 
 	<xp:button value="保存" id="button1">
		<xp:eventHandler event="onclick" submit="true"
			refreshMode="complete">
			<xp:this.action>
				<xp:saveDocument var="document1"></xp:saveDocument>
			</xp:this.action>
		</xp:eventHandler>
	</xp:button>
	
</xp:view>

見た目がこんな感じ。何の変哲もありません。

至って普通のXPage
至って普通のXPage

それでは保存を押してみると、保存することが出来ました、、、が中身を覗いてみるとJSONがHTMLコードに変換されてしまいました。これではせっかくのJSONデータをそのまま扱えなくなってしまいます。これはXPagesではリッチテキストフィールドにCKEditorと呼ばれるHTMLエディタを使っているため保存時に自動でコンバートされてしまうのが原因でした。

JSONがHTMLコードに変換されてしまう
JSONがHTMLコードに変換されてしまう

テキストエリアでリッチテキストを操作

XPagesには複数行編集ボックス(xp:inputTextarea)というものがあります。これを使うとHTMLのテキストエリアが出力されます。今回の一番のポイントになるところですが、リッチテキストフィールドを複数行編集ボックスで扱うことによりCKEditor出力をさせない方法を採用します。

しかし、単純に複数行編集ボックスのデータバインド先にリッチテキストフィールドを指定してもXPagesは保存時にテキストフィールドとして保存を仕掛けに行くため、フィールドタイプが違うことによるエラーが発生し保存されません。

xpage inputTextArea Save32KBOverData

複数行編集ボックスでリッチテキストを扱うためのおまじない

やっと結論です。ブログを読むのが面倒な人はこのコードだけコピペしてください(笑)。

<?xml version="1.0" encoding="UTF-8"?>
<xp:view xmlns:xp="http://www.ibm.com/xsp/core">

	<xp:this.data>
		<xp:dominoDocument var="document1" action="editDocument"
			formName="Contact" computeWithForm="both">
		</xp:dominoDocument>
	</xp:this.data>

	<xp:inputTextarea id="CanvasJson" value="#{document1.CanvasJson}">
	    <xp:this.converter>
	        <xp:customConverter getAsString="#{javascript:value.getContentAsText()}">
	            <xp:this.getAsObject><![CDATA[#{javascript:com.ibm.xsp.http.MimeMultipart.fromHTML(value)}]]></xp:this.getAsObject>
	        </xp:customConverter>
	    </xp:this.converter>
	</xp:inputTextarea>
 
 	<xp:button value="保存" id="button1">
		<xp:eventHandler event="onclick" submit="true"
			refreshMode="complete">
			<xp:this.action>
				<xp:saveDocument var="document1"></xp:saveDocument>
			</xp:this.action>
		</xp:eventHandler>
	</xp:button>
	
</xp:view>

まずgetAsStringvalue.getContentAsText()をすることでリッチテキストコンテンツをテキストとして表示してやります。これは関数名からも察しがつきますね。

次にxp:this.getAsObjectcom.ibm.xsp.http.MimeMultipart.fromHTML(value)をすることで保存時にリッチテキストフィールドとして扱われるMIME形式にコンバートしてやります。

com.ibm.xsp.http.MimeMultipart.fromHTML()を使う箇所は中々高度なため思いきにくいと思います。自分も色々と調べてやっとこの答えにたどり着きました。

(おまけ)CSJSでテキストエリアにJSONを格納する方法

おまけでCSJSでテキストエリアにJSONを格納する方法の例を以下に記載します。以下の例では保存時にCSJSでテキストエリアにJSONデータを格納する処理をしています。

	<xp:button value="保存" id="button1">
		<xp:eventHandler event="onclick" submit="true"
			refreshMode="complete">
			<xp:this.action>
				<xp:saveDocument var="document1"></xp:saveDocument>
			</xp:this.action>
			<xp:this.script><![CDATA[
dojo.byId("#{id:CanvasJson}").innerText = JSON.stringify(this.__canvas.toJSON());
]]></xp:this.script>
		</xp:eventHandler>
	</xp:button>

こんな感じです。ハイライトの行をみて「まだDojo使ってるのかよっ」と思わないでください(笑) ここはjQueryでもなんでもお好きなように。後半部分のthis.__canvas.toJSON()も無視です。この関数がJSONデータを返すと思ってください。要点はJSON.stringify()関数を使って文字列化したJSONデータをテキストエリアに格納している、という内容です。

終わりに

今回もニッチな内容でしたが、いつか誰かの役に立つことを願ってます(笑) XPAGESの技術系でネタを書くとこんな感じになりがちですがまたネタを見つけたら書きたいと思います。