var parse_content_xml = (function() { var number_formats = { /* ods name: [short ssf fmt, long ssf fmt] */ day: ["d", "dd"], month: ["m", "mm"], year: ["y", "yy"], hours: ["h", "hh"], minutes: ["m", "mm"], seconds: ["s", "ss"], "am-pm": ["A/P", "AM/PM"], "day-of-week": ["ddd", "dddd"] }; return function pcx(d, opts) { var str = xlml_normalize(d); var state/*:Array*/ = [], tmp; var tag/*:: = {}*/; var NFtag = {name:""}, NF = "", pidx = 0; var sheetag/*:: = {name:""}*/; var Sheets = {}, SheetNames/*:Array*/ = [], ws = {}; var Rn, q/*:: = ({t:"", v:null, z:null, w:""}:any)*/; var ctag = {value:""}; var textp = "", textpidx = 0, textptag/*:: = {}*/; var R = -1, C = -1, range = {s: {r:1000000,c:10000000}, e: {r:0, c:0}}; var number_format_map = {}; var merges = [], mrange = {}, mR = 0, mC = 0; var arrayf = []; var rept = 1, isstub = false; var i = 0; xlmlregex.lastIndex = 0; while((Rn = xlmlregex.exec(str))) switch(Rn[3]) { case 'table': // 9.1.2 if(Rn[1]==='/') { if(range.e.c >= range.s.c && range.e.r >= range.s.r) ws['!ref'] = get_utils().encode_range(range); if(merges.length) ws['!merges'] = merges; sheetag.name = utf8read(sheetag.name); SheetNames.push(sheetag.name); Sheets[sheetag.name] = ws; } else if(Rn[0].charAt(Rn[0].length-2) !== '/') { sheetag = parsexmltag(Rn[0], false); R = C = -1; range.s.r = range.s.c = 10000000; range.e.r = range.e.c = 0; ws = {}; merges = []; } break; case 'table-row': // 9.1.3 if(Rn[1] === '/') break; ++R; C = -1; break; case 'covered-table-cell': // 9.1.5 table:covered-table-cell ++C; break; /* stub */ case 'table-cell': if(Rn[0].charAt(Rn[0].length-2) === '/') { ctag = parsexmltag(Rn[0], false); if(ctag['number-columns-repeated']) C+= parseInt(ctag['number-columns-repeated'], 10); else ++C; } else if(Rn[1]!=='/') { ++C; rept = 1; if(C > range.e.c) range.e.c = C; if(R > range.e.r) range.e.r = R; if(C < range.s.c) range.s.c = C; if(R < range.s.r) range.s.r = R; ctag = parsexmltag(Rn[0], false); q = ({t:ctag['value-type'], v:null/*:: , z:null, w:""*/}/*:any*/); if(opts.cellFormula) { if(ctag['number-matrix-columns-spanned'] && ctag['number-matrix-rows-spanned']) { mR = parseInt(ctag['number-matrix-rows-spanned'],10) || 0; mC = parseInt(ctag['number-matrix-columns-spanned'],10) || 0; mrange = {s: {r:R,c:C}, e:{r:R + mR-1,c:C + mC-1}}; q.F = get_utils().encode_range(mrange); arrayf.push([mrange, q.F]); } if(ctag.formula) q.f = ods_to_csf_formula(ctag.formula); else for(i = 0; i < arrayf.length; ++i) if(R >= arrayf[i][0].s.r && R <= arrayf[i][0].e.r) if(C >= arrayf[i][0].s.c && C <= arrayf[i][0].e.c) q.F = arrayf[i][1]; } if(ctag['number-columns-spanned'] || ctag['number-rows-spanned']) { mR = parseInt(ctag['number-rows-spanned'],10) || 0; mC = parseInt(ctag['number-columns-spanned'],10) || 0; mrange = {s: {r:R,c:C}, e:{r:R + mR-1,c:C + mC-1}}; merges.push(mrange); } /* 19.675.2 table:number-columns-repeated */ if(ctag['number-columns-repeated']) rept = parseInt(ctag['number-columns-repeated'], 10); /* 19.385 office:value-type */ switch(q.t) { case 'boolean': q.t = 'b'; q.v = parsexmlbool(ctag['boolean-value']); break; case 'float': q.t = 'n'; q.v = parseFloat(ctag.value); break; case 'percentage': q.t = 'n'; q.v = parseFloat(ctag.value); break; case 'currency': q.t = 'n'; q.v = parseFloat(ctag.value); break; case 'date': q.t = 'n'; q.v = datenum(ctag['date-value']); q.z = 'm/d/yy'; break; case 'time': q.t = 'n'; q.v = parse_isodur(ctag['time-value'])/86400; break; default: if(q.t === 'string' || !q.t) { q.t = 's'; if(ctag['string-value'] != null) textp = ctag['string-value']; } else throw new Error('Unsupported value type ' + q.t); } } else { isstub = false; if(q.t === 's') { q.v = textp || ''; isstub = textpidx == 0; } if(textp) q.w = textp; if(!isstub || opts.cellStubs) { if(!(opts.sheetRows && opts.sheetRows < R)) { ws[get_utils().encode_cell({r:R,c:C})] = q; while(--rept > 0) ws[get_utils().encode_cell({r:R,c:++C})] = dup(q); if(range.e.c <= C) range.e.c = C; } } else { C += rept; rept = 0; } q = {/*:: t:"", v:null, z:null, w:""*/}; textp = ""; } break; // 9.1.4 /* pure state */ case 'document-content': // 3.1.3.2 case 'spreadsheet': // 3.7 case 'scripts': // 3.12 case 'font-face-decls': // 3.14 if(Rn[1]==='/'){if((tmp=state.pop())[0]!==Rn[3]) throw "Bad state: "+tmp;} else if(Rn[0].charAt(Rn[0].length-2) !== '/') state.push([Rn[3], true]); break; /* ignore state */ case 'shapes': // 9.2.8 case 'frame': // 10.4.2 case 'text-box': // 10.4.3 case 'image': // 10.4.4 case 'data-pilot-tables': // 9.6.2 case 'list-style': // 16.30 case 'form': // 13.13 case 'dde-links': // 9.8 case 'annotation': // 14.1 if(Rn[1]==='/'){if((tmp=state.pop())[0]!==Rn[3]) throw "Bad state: "+tmp;} else if(Rn[0].charAt(Rn[0].length-2) !== '/') state.push([Rn[3], false]); textp = ""; textpidx = 0; break; case 'number-style': // 16.27.2 case 'percentage-style': // 16.27.9 case 'date-style': // 16.27.10 case 'time-style': // 16.27.18 if(Rn[1]==='/'){ number_format_map[NFtag.name] = NF; if((tmp=state.pop())[0]!==Rn[3]) throw "Bad state: "+tmp; } else if(Rn[0].charAt(Rn[0].length-2) !== '/') { NF = ""; NFtag = parsexmltag(Rn[0], false); state.push([Rn[3], true]); } break; case 'script': break; // 3.13 case 'automatic-styles': break; // 3.15.3 case 'style': break; // 16.2 case 'map': break; // 16.3 case 'font-face': break; // 16.21 case 'paragraph-properties': break; // 17.6 case 'table-properties': break; // 17.15 case 'table-column-properties': break; // 17.16 case 'table-row-properties': break; // 17.17 case 'table-cell-properties': break; // 17.18 case 'number': // 16.27.3 switch(state[state.length-1][0]) { case 'time-style': case 'date-style': tag = parsexmltag(Rn[0], false); NF += number_formats[Rn[3]][tag.style==='long'?1:0]; break; } break; case 'fraction': break; // TODO 16.27.6 case 'day': // 16.27.11 case 'month': // 16.27.12 case 'year': // 16.27.13 case 'era': // 16.27.14 case 'day-of-week': // 16.27.15 case 'week-of-year': // 16.27.16 case 'quarter': // 16.27.17 case 'hours': // 16.27.19 case 'minutes': // 16.27.20 case 'seconds': // 16.27.21 case 'am-pm': // 16.27.22 switch(state[state.length-1][0]) { case 'time-style': case 'date-style': tag = parsexmltag(Rn[0], false); NF += number_formats[Rn[3]][tag.style==='long'?1:0]; break; } break; case 'boolean-style': break; // 16.27.23 case 'boolean': break; // 16.27.24 case 'text-style': break; // 16.27.25 case 'text': // 16.27.26 if(Rn[0].substr(-2) === "/>") break; else if(Rn[1]==="/") switch(state[state.length-1][0]) { case 'number-style': case 'date-style': case 'time-style': NF += str.slice(pidx, Rn.index); break; } else pidx = Rn.index + Rn[0].length; break; case 'text-content': break; // 16.27.27 case 'text-properties': break; // 16.27.27 case 'body': break; // 3.3 16.9.6 19.726.3 case 'forms': break; // 12.25.2 13.2 case 'table-column': break; // 9.1.6 case 'null-date': break; // 9.4.2 TODO: date1904 case 'graphic-properties': break; // 17.21 case 'calculation-settings': break; // 9.4.1 case 'named-expressions': break; // 9.4.11 case 'named-range': break; // 9.4.12 case 'named-expression': break; // 9.4.13 case 'sort': break; // 9.4.19 case 'sort-by': break; // 9.4.20 case 'sort-groups': break; // 9.4.22 case 'span': break; // case 'line-break': break; // 6.1.5 case 'p': if(Rn[1]==='/') textp = parse_text_p(str.slice(textpidx,Rn.index), textptag); else { textptag = parsexmltag(Rn[0], false); textpidx = Rn.index + Rn[0].length; } break; // case 's': break; // case 'date': break; // <*:date> case 'object': break; // 10.4.6.2 case 'title': break; // <*:title> case 'desc': break; // <*:desc> case 'table-source': break; // 9.2.6 case 'iteration': break; // 9.4.3 case 'content-validations': break; // 9.4.4 case 'database-range': break; // 9.4.15 case 'filter': break; // 9.5.2 case 'filter-and': break; // 9.5.3 case 'filter-or': break; // 9.5.4 case 'filter-condition': break; // 9.5.5 case 'list-level-style-bullet': break; // 16.31 case 'property': break; // 13.8 case 'a': break; // 6.1.8 hyperlink /* non-standard */ case 'table-protection': break; case 'data-pilot-grand-total': break; //