001package com.hfg.xml.msofficexml.xlsx.part; 002 003import java.io.BufferedInputStream; 004import java.util.List; 005 006import com.hfg.util.collection.BiHashMap; 007import com.hfg.util.collection.BiMap; 008import com.hfg.xml.XMLDoc; 009import com.hfg.xml.XMLNode; 010import com.hfg.xml.XMLTag; 011import com.hfg.xml.XMLUtil; 012import com.hfg.xml.msofficexml.part.OfficeXMLPart; 013import com.hfg.xml.msofficexml.xlsx.SsmlRelationshipType; 014import com.hfg.xml.msofficexml.xlsx.Xlsx; 015import com.hfg.xml.msofficexml.xlsx.spreadsheetml.SsmlTextRun; 016import com.hfg.xml.msofficexml.xlsx.spreadsheetml.SsmlXML; 017import com.hfg.xml.msofficexml.xlsx.spreadsheetml.SsmlXMLTag; 018 019//------------------------------------------------------------------------------ 020/** 021 Office Open XML format Excel shared string part. 022 023 @author J. Alex Taylor, hairyfatguy.com 024 */ 025//------------------------------------------------------------------------------ 026// com.hfg XML/HTML Coding Library 027// 028// This library is free software; you can redistribute it and/or 029// modify it under the terms of the GNU Lesser General Public 030// License as published by the Free Software Foundation; either 031// version 2.1 of the License, or (at your option) any later version. 032// 033// This library is distributed in the hope that it will be useful, 034// but WITHOUT ANY WARRANTY; without even the implied warranty of 035// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU 036// Lesser General Public License for more details. 037// 038// You should have received a copy of the GNU Lesser General Public 039// License along with this library; if not, write to the Free Software 040// Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA 041// 042// J. Alex Taylor, President, Founder, CEO, COO, CFO, OOPS hairyfatguy.com 043// jataylor@hairyfatguy.com 044//------------------------------------------------------------------------------ 045 046public class SharedStringsPart extends OfficeXMLPart 047{ 048 private XMLTag mSharedStringsTableTag; 049 050 private BiMap<String, Integer> mStringIndexMap = new BiHashMap<>(); 051 052 //########################################################################## 053 // CONSTRUCTORS 054 //########################################################################## 055 056 //--------------------------------------------------------------------------- 057 public SharedStringsPart(Xlsx inXlsx) 058 { 059 super(inXlsx); 060 setFile(SsmlXML.SHARED_STRINGS_FILE); 061 062 // Register the content type 063 inXlsx.getContentTypesPart().addOverride(this, SsmlContentType.SPREADSHEET_SHARED_STRINGS); 064 065 // Register the relationship 066 inXlsx.getWorkbookRelationshipPart().addRelationship(SsmlRelationshipType.SHARED_STRINGS, this); 067 068 mSharedStringsTableTag = new SsmlSharedStringsTable(inXlsx); 069 setRootNode(mSharedStringsTableTag); 070 } 071 072 //--------------------------------------------------------------------------- 073 public SharedStringsPart(Xlsx inXlsx, BufferedInputStream inStream) 074 { 075 this(inXlsx); 076 077 XMLDoc doc = new XMLDoc(inStream); 078 mSharedStringsTableTag = (XMLTag) doc.getRootNode(); 079 080 081 int index = 0; 082 for (XMLNode stringItemTag : mSharedStringsTableTag.getSubtagsByName(SsmlXML.STRING_ITEM)) 083 { 084 // Strip out the content // TODO: Return complex content (text runs) in their native state 085 StringBuilder buffer = new StringBuilder(); 086 for (XMLNode subtag : (List<XMLNode>) (Object) stringItemTag.getSubtags()) 087 { 088 if (subtag.getTagName().equals(SsmlXML.TEXT.getLocalName())) 089 { 090 buffer.append(subtag.getContent()); 091 } 092 else if (subtag.getTagName().equals(SsmlXML.TEXT_RUN.getLocalName())) 093 { 094 for (XMLNode textTag : subtag.getSubtagsByName(SsmlXML.TEXT)) 095 { 096 buffer.append(textTag.getContent()); 097 } 098 } 099 } 100 101 // Using unescapeEntities() instead of getUnescapedContent() because we were observing additional escaping like " 102 mStringIndexMap.put(XMLUtil.unescapeEntities(buffer.toString()), index++); 103 } 104 } 105 106 //########################################################################## 107 // PUBLIC METHODS 108 //########################################################################## 109 110 //--------------------------------------------------------------------------- 111 public int defineString(SsmlTextRun inValue) 112 { 113 Integer index = mStringIndexMap.get(inValue.toXML()); 114 if (null == index) 115 { 116 // It's a new string value 117 index = mStringIndexMap.size(); 118 mStringIndexMap.put(inValue.toXML(), index); 119 120 XMLTag stringItemTag = new XMLTag(SsmlXML.STRING_ITEM); 121 stringItemTag.addSubtag(inValue); 122 123 mSharedStringsTableTag.addSubtag(stringItemTag); 124 mSharedStringsTableTag.setAttribute(SsmlXML.COUNT_ATT, mStringIndexMap.size()); 125 mSharedStringsTableTag.setAttribute(SsmlXML.UNIQUE_COUNT_ATT, mStringIndexMap.size()); 126 } 127 128 return index; 129 } 130 131 //--------------------------------------------------------------------------- 132 public int defineString(List<SsmlTextRun> inValue) 133 { 134 StringBuilder xml = new StringBuilder(); 135 for (SsmlTextRun run : inValue) 136 { 137 xml.append(run.toXML()); 138 } 139 140 Integer index = mStringIndexMap.get(xml.toString()); 141 if (null == index) 142 { 143 // It's a new string value 144 index = mStringIndexMap.size(); 145 mStringIndexMap.put(xml.toString(), index); 146 147 XMLTag stringItemTag = new XMLTag(SsmlXML.STRING_ITEM); 148 stringItemTag.addSubtags(inValue); 149 150 mSharedStringsTableTag.addSubtag(stringItemTag); 151 mSharedStringsTableTag.setAttribute(SsmlXML.COUNT_ATT, mStringIndexMap.size()); 152 mSharedStringsTableTag.setAttribute(SsmlXML.UNIQUE_COUNT_ATT, mStringIndexMap.size()); 153 } 154 155 return index; 156 } 157 158 //--------------------------------------------------------------------------- 159 public int defineString(String inValue) 160 { 161 Integer index = mStringIndexMap.get(inValue); 162 if (null == index) 163 { 164 // It's a new string value 165 index = mStringIndexMap.size(); 166 mStringIndexMap.put(inValue, index); 167 168 XMLTag textTag = new XMLTag(SsmlXML.TEXT); 169 textTag.setContent(inValue); 170 171 XMLTag stringItemTag = new XMLTag(SsmlXML.STRING_ITEM); 172 stringItemTag.addSubtag(textTag); 173 174 mSharedStringsTableTag.addSubtag(stringItemTag); 175 mSharedStringsTableTag.setAttribute(SsmlXML.COUNT_ATT, mStringIndexMap.size()); 176 mSharedStringsTableTag.setAttribute(SsmlXML.UNIQUE_COUNT_ATT, mStringIndexMap.size()); 177 } 178 179 return index; 180 } 181 182 //--------------------------------------------------------------------------- 183 public String getString(int inIndex) 184 { 185 return mStringIndexMap.getKey(inIndex); 186 } 187 188 189 private class SsmlSharedStringsTable extends SsmlXMLTag 190 { 191 //--------------------------------------------------------------------------- 192 public SsmlSharedStringsTable(Xlsx inXlsx) 193 { 194 super(SsmlXML.SHARED_STRING_TABLE, inXlsx); 195 } 196 } 197}