Calcドキュメントのセル情報はtable:table-cell要素に記録されています。 Calcに表示される内容は子のtext:p要素に書き出されます。 text:p要素の内容は書式コードに従って整形された後の文字列です。 例えば数字が記録されたセルで「3桁ごとにコンマを打ち、頭に円記号を付ける」などの変換がされた後の文字列になります。
整形される前の値を取り出すにはtable:table-cellタグの属性を調べます。 office:value-type属性にセルに書かれている値のタイプが記録されています。 タイプに対応したもう1つの属性があるので、その値を読みます。
タイプには次のようなものがあります。(よく使いそうなもののみ抜粋)
| value-type | 対応する属性 |
|---|---|
| float | office:value |
| date | office:date-value |
| boolean | office:boolean-value |
| string | office:string-value (式を使ったときのみ) |
例えば、2,980円と書かれたセルはxmlでは次のようになります。
<table:table-cell office:value-type="float" office:value="2980">
<text:p>2,980円</text:p>
</table:table-cell>
Integer.parseIntをするときはoffice:value属性の値を使った方がよいでしょう。 整形をCalcに任せて、書式のコーディングをしないのならtext:pの内容を使った方が楽です。
セルに式を書いた場合、式の内容はtable:table-cellタグのtable:formula属性に記録されます。 式の計算結果はvalue属性に出力されます。 Calcが計算した結果を利用するだけなら、意識する必要はありません。
// 各セルの内容を文字列に変換する
private String parseCellElement(Element cellElement)
{
// セルに表示されている文字列を取り出すだけの場合はこれ
// return cellElement.getTextContent();
// セルのタイプで場合分け
String valueType = cellElement.getAttribute("office:value-type");
String res = null;
if(valueType.equals("float") )
{
res = cellElement.getAttribute("office:value");
}
else if(valueType.equals("date") )
{
res = cellElement.getAttribute("office:date-value");
}
else if(valueType.equals("boolean") )
{
res = cellElement.getAttribute("office:boolean-value");
}
else
{
// 子ノードの「text:p」タグからテキスト情報を読む
if(cellElement.hasChildNodes() )
{
StringBuilder textp;
textp = parseTextpElement( (Element)cellElement.getFirstChild() );
res = textp.toString();
}
else
{
res = "";
}
}
return res;
}
text:p要素にはテキストノードだけではなく文字修飾やハイパーリンクのタグが含まれています。 文字修飾はtext:spanという範囲タグで表現されます。 text:style-nameという属性にスタイル名が記録されています。 ハイパーリンクはtext:aというアンカータグで表現されます。 リンク先はxlink:href属性に記録されています。
<text:p>
リンク
<text:span text:style-name="T1">の</text:span>
テスト ...
<text:a xlink:href="http://www15.plala.or.jp/kichijitsu/index.html">
片鱗懐古のページ
</text:a>
へ移動
</text:p>
text:spanタグは文字列の一部を修飾するとき使用されます。 セルに含まれる文字列全体のスタイルが設定されている場合、table:table-cellタグにスタイルが記述されるようです。
spanとアンカーをhtmlのタグに変更し、文字列で返すコードは以下のようになります。
private StringBuilder parseTextpElement(Element textpElement)
{
StringBuilder res = new StringBuilder();
NodeList nodeList = textpElement.getChildNodes();
int nodeLen = nodeList.getLength();
for(int i = 0; i < nodeLen; i++)
{
Node node = nodeList.item(i);
Short nodeType = node.getNodeType();
switch(nodeType)
{
// テキストノードはそのまま追加
case Node.TEXT_NODE:
res.append(node.getNodeValue() );
break;
case Node.ELEMENT_NODE:
String nodeName = node.getNodeName();
Element elem = (Element)node;
// 外部リンクはhtmlのアンカータグに変更
if(nodeName.equals("text:a") )
{
String href = elem.getAttribute("xlink:href");
res.append("<a href=\"");
res.append(href);
res.append("\">");
res.append(elem.getFirstChild().getNodeValue() );
res.append("</a>");
}
// 文字修飾はhtmlのspanタグに変更
else if(nodeName.equals("text:span") )
{
String styleName = elem.getAttribute("text:style-name");
if(styleName.isEmpty() )
{
res.append("<span>");
}
else
{
res.append("<span class=\"accent\">");
}
res.append(parseTextpElement(elem) );
res.append("</span>");
}
// それ以外は再帰で子ノードを調べる
else
{
res.append(parseTextpElement(elem) );
}
break;
}
}
return res;
}