Use extend 'excelHtml5', and simply modify customizeData function
In the customizeData function, there is 3 parameter of array, which is header,body, and fotter
Default action is the header parameter takes the last our table header,
if our table has multi header then we put replace header parameter with the first header , and put the rest header into body parameter
extend: 'excelHtml5',
customizeData: function(data) {
var namatabel = "myTable";
var colLength = $("#" + namatabel + " thead:first tr:last th").length;
var jmlheader = $('#'+namatabel+' thead:first tr').length;
if (jmlheader > 1) {
data.body.unshift(data.header);
data.header=[""];
var j=0,rspan=[];
for(j=0;j<jmlheader;j++){
rspan[j]=[];
for(var i=0;i<colLength;i++){
rspan[j][i]=0;
}
}
var colSpan=0,rowSpan=0;
var topHeader = [],thisHead=[],thiscol=0,thisrow=0,jspan=0;
for(j=1;j<=(jmlheader-1);j++){
thisHead=[],thiscol=0;jspan=0;
$('#'+namatabel).find("thead:first>tr:nth-child("+j+")>th").each(function (index, element) {
colSpan = parseInt(element.getAttribute("colSpan"));
rowSpan = parseInt(element.getAttribute("rowSpan"));
jspan=jspan+colSpan;
if(rspan[thisrow][thiscol]>0){
for(var i=0;i<rspan[thisrow][thiscol];i++){
thisHead.push("");
}
}
if(rowSpan>1){
jspan=jspan-colSpan;
for (var i=thisrow+1; i < jmlheader; i++) {
rspan[i][jspan]=colSpan;
}
}
thisHead.push(element.innerHTML.toUpperCase());
for (var i = 0; i < colSpan - 1; i++) {
thisHead.push("");
}
thiscol++;
});
thisrow++;
if(j==1){
data.header=thisHead;
}else{
topHeader.push(thisHead);
}
};
thiscol=topHeader.length;
for(j=(thiscol-1);j>=0;j--){
data.body.unshift(topHeader[j]);
};
}
},
},
That code support rowspan and colspan too
And for print button :
extend: 'print',
customize:function(win) {
var namatabel = "myTable";
var jmlheader = $('#'+namatabel+' thead:first tr').length;
if(jmlheader>1){
$(win.document.body).find("table").find("thead").empty();
$(win.document.body).find("table").find("thead").append($('#'+namatabel+' thead:first').html());
}
},