docs: function write_ws_xlml_table(ws, opts, idx, wb) {
  	if(!ws['!ref']) return "";
  	var range = safe_decode_range(ws['!ref']);
  	var marr = ws['!merges'] || [], mi = 0;
  	var o = [];
  	if(ws['!cols']) ws['!cols'].forEach(function(n, i) {
  		process_col(n);
  		var w = !!n.width;
  		var p = col_obj_w(i, n);
  		var k = {"ss:Index":i+1};
  		if(w) k['ss:Width'] = width2px(p.width);
  		if(n.hidden) k['ss:Hidden']="1";
  		o.push(writextag("Column",null,k));
  	});
  	var dense = Array.isArray(ws);
  	for(var R = range.s.r; R <= range.e.r; ++R) {
  		var row = [write_ws_xlml_row(R, (ws['!rows']||[])[R])];
  		for(var C = range.s.c; C <= range.e.c; ++C) {
  			var skip = false;
  			for(mi = 0; mi != marr.length; ++mi) {
  				if(marr[mi].s.c > C) continue;
  				if(marr[mi].s.r > R) continue;
  				if(marr[mi].e.c < C) continue;
  				if(marr[mi].e.r < R) continue;
  				if(marr[mi].s.c != C || marr[mi].s.r != R) skip = true;
  				break;
  			}
  			if(skip) continue;
  			var addr = {r:R,c:C};
  			var ref = encode_cell(addr), cell = dense ? (ws[R]||[])[C] : ws[ref];
  			row.push(write_ws_xlml_cell(cell, ref, ws, opts, idx, wb, addr));
  		}
  		row.push("</Row>");
  		if(row.length > 2) o.push(row.join(""));
  	}
  	return o.join("");
  }