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; }