public XMergeCell(XMergeCell mergeCell) { this.Width = mergeCell.Width; this.Height = mergeCell.Height; this.X1 = mergeCell.X1; this.Y1 = mergeCell.Y1; this.X2 = mergeCell.X2; this.Y2 = mergeCell.Y2; this.MergeCell = mergeCell.MergeCell; }
private void GetMercells(XmlDocument doc, XmlNode worksheet) { var mergeCells = doc.SelectSingleNode($"/x:worksheet/x:mergeCells", _ns); if (mergeCells != null) { var newMergeCells = mergeCells.Clone(); //mergeCells.RemoveAll(); worksheet.RemoveChild(mergeCells); foreach (XmlElement cell in newMergeCells) { var @ref = cell.Attributes["ref"].Value; var mergerCell = new XMergeCell(cell); this.XMergeCellInfos[mergerCell.XY1] = mergerCell; } } }
private void WriteSheetXml(Stream stream, XmlDocument doc, XmlNode sheetData) { //Q.Why so complex? //A.Because try to use string stream avoid OOM when rendering rows sheetData.RemoveAll(); sheetData.InnerText = "{{{{{{split}}}}}}"; //TODO: bad code smell var prefix = string.IsNullOrEmpty(sheetData.Prefix) ? "" : $"{sheetData.Prefix}:"; var endPrefix = string.IsNullOrEmpty(sheetData.Prefix) ? "" : $":{sheetData.Prefix}"; //![image](https://user-images.githubusercontent.com/12729184/115000066-fd02b300-9ed4-11eb-8e65-bf0014015134.png) var contents = doc.InnerXml.Split(new string[] { $"<{prefix}sheetData>{{{{{{{{{{{{split}}}}}}}}}}}}</{prefix}sheetData>" }, StringSplitOptions.None);; using (var writer = new StreamWriter(stream, Encoding.UTF8)) { writer.Write(contents[0]); writer.Write($"<{prefix}sheetData>"); // prefix problem #region Generate rows and cells int originRowIndex; int rowIndexDiff = 0; foreach (var rowInfo in XRowInfos) { var row = rowInfo.Row; //TODO: some xlsx without r originRowIndex = int.Parse(row.GetAttribute("r")); var newRowIndex = originRowIndex + rowIndexDiff; if (rowInfo.CellIEnumerableValues != null) { var first = true; var iEnumerableIndex = 0; foreach (var item in rowInfo.CellIEnumerableValues) { iEnumerableIndex++; var newRow = row.Clone() as XmlElement; newRow.SetAttribute("r", newRowIndex.ToString()); newRow.InnerXml = row.InnerXml.Replace($"{{{{$rowindex}}}}", newRowIndex.ToString()); if (rowInfo.IsDictionary) { var dic = item as IDictionary <string, object>; foreach (var propInfo in rowInfo.PropsMap) { var key = $"{{{{{rowInfo.IEnumerablePropName}.{propInfo.Key}}}}}"; if (item == null) //![image](https://user-images.githubusercontent.com/12729184/114728510-bc3e5900-9d71-11eb-9721-8a414dca21a0.png) { newRow.InnerXml = newRow.InnerXml.Replace(key, ""); continue; } var cellValue = dic[propInfo.Key]; if (cellValue == null) { newRow.InnerXml = newRow.InnerXml.Replace(key, ""); continue; } var cellValueStr = ExcelOpenXmlUtils.EncodeXML(cellValue?.ToString()); var type = propInfo.Value.UnderlyingTypePropType; if (type == typeof(bool)) { cellValueStr = (bool)cellValue ? "1" : "0"; } else if (type == typeof(DateTime)) { //c.SetAttribute("t", "d"); cellValueStr = ((DateTime)cellValue).ToString("yyyy-MM-dd HH:mm:ss"); } //TODO: ![image](https://user-images.githubusercontent.com/12729184/114848248-17735880-9e11-11eb-8258-63266bda0a1a.png) newRow.InnerXml = newRow.InnerXml.Replace(key, cellValueStr); } } else if (rowInfo.IsDataTable) { var datarow = item as DataRow; foreach (var propInfo in rowInfo.PropsMap) { var key = $"{{{{{rowInfo.IEnumerablePropName}.{propInfo.Key}}}}}"; if (item == null) //![image](https://user-images.githubusercontent.com/12729184/114728510-bc3e5900-9d71-11eb-9721-8a414dca21a0.png) { newRow.InnerXml = newRow.InnerXml.Replace(key, ""); continue; } var cellValue = datarow[propInfo.Key]; if (cellValue == null) { newRow.InnerXml = newRow.InnerXml.Replace(key, ""); continue; } var cellValueStr = ExcelOpenXmlUtils.EncodeXML(cellValue?.ToString()); var type = propInfo.Value.UnderlyingTypePropType; if (type == typeof(bool)) { cellValueStr = (bool)cellValue ? "1" : "0"; } else if (type == typeof(DateTime)) { //c.SetAttribute("t", "d"); cellValueStr = ((DateTime)cellValue).ToString("yyyy-MM-dd HH:mm:ss"); } //TODO: ![image](https://user-images.githubusercontent.com/12729184/114848248-17735880-9e11-11eb-8258-63266bda0a1a.png) newRow.InnerXml = newRow.InnerXml.Replace(key, cellValueStr); } } else { foreach (var propInfo in rowInfo.PropsMap) { var prop = propInfo.Value.PropertyInfo; var key = $"{{{{{rowInfo.IEnumerablePropName}.{prop.Name}}}}}"; if (item == null) //![image](https://user-images.githubusercontent.com/12729184/114728510-bc3e5900-9d71-11eb-9721-8a414dca21a0.png) { newRow.InnerXml = newRow.InnerXml.Replace(key, ""); continue; } var cellValue = prop.GetValue(item); if (cellValue == null) { newRow.InnerXml = newRow.InnerXml.Replace(key, ""); continue; } var cellValueStr = ExcelOpenXmlUtils.EncodeXML(cellValue?.ToString()); var type = Nullable.GetUnderlyingType(prop.PropertyType) ?? prop.PropertyType; if (type == typeof(bool)) { cellValueStr = (bool)cellValue ? "1" : "0"; } else if (type == typeof(DateTime)) { //c.SetAttribute("t", "d"); cellValueStr = ((DateTime)cellValue).ToString("yyyy-MM-dd HH:mm:ss"); } //TODO: ![image](https://user-images.githubusercontent.com/12729184/114848248-17735880-9e11-11eb-8258-63266bda0a1a.png) newRow.InnerXml = newRow.InnerXml.Replace(key, cellValueStr); } } // note: only first time need add diff ![image](https://user-images.githubusercontent.com/12729184/114494728-6bceda80-9c4f-11eb-9685-8b5ed054eabe.png) if (!first) { //rowIndexDiff++; rowIndexDiff = rowIndexDiff + (rowInfo.IEnumerableMercell == null ? 1 : rowInfo.IEnumerableMercell.Height); //TODO:base on the merge size } first = false; var mergeBaseRowIndex = newRowIndex; newRowIndex = newRowIndex + (rowInfo.IEnumerableMercell == null ? 1 : rowInfo.IEnumerableMercell.Height); writer.Write(CleanXml(newRow.OuterXml, endPrefix)); newRow = null; //mergecells if (rowInfo.RowMercells != null) { foreach (var mergeCell in rowInfo.RowMercells) { var newMergeCell = new XMergeCell(mergeCell); newMergeCell.Y1 = newMergeCell.Y1 + rowIndexDiff; newMergeCell.Y2 = newMergeCell.Y2 + rowIndexDiff; this.NewXMergeCellInfos.Add(newMergeCell); } // Last merge one don't add new row, or it'll get duplicate result like : https://github.com/shps951023/MiniExcel/issues/207#issuecomment-824550950 if (iEnumerableIndex == rowInfo.CellIEnumerableValuesCount) { continue; } // https://github.com/shps951023/MiniExcel/issues/207#issuecomment-824518897 for (int i = 1; i < rowInfo.IEnumerableMercell.Height; i++) { mergeBaseRowIndex++; var _newRow = row.Clone() as XmlElement; _newRow.SetAttribute("r", mergeBaseRowIndex.ToString()); var cs = _newRow.SelectNodes($"x:c", _ns); // all v replace by empty // TODO: remove c/v foreach (XmlElement _c in cs) { _c.RemoveAttribute("t"); foreach (XmlNode ch in _c.ChildNodes) { _c.RemoveChild(ch); } } _newRow.InnerXml = _newRow.InnerXml.Replace($"{{{{$rowindex}}}}", mergeBaseRowIndex.ToString()); writer.Write(CleanXml(_newRow.OuterXml, endPrefix)); } } } } else { row.SetAttribute("r", newRowIndex.ToString()); row.InnerXml = row.InnerXml.Replace($"{{{{$rowindex}}}}", newRowIndex.ToString()); writer.Write(CleanXml(row.OuterXml, endPrefix)); //mergecells if (rowInfo.RowMercells != null) { foreach (var mergeCell in rowInfo.RowMercells) { var newMergeCell = new XMergeCell(mergeCell); newMergeCell.Y1 = newMergeCell.Y1 + rowIndexDiff; newMergeCell.Y2 = newMergeCell.Y2 + rowIndexDiff; this.NewXMergeCellInfos.Add(newMergeCell); } } } // get the row's all mergecells then update the rowindex } #endregion writer.Write($"</{prefix}sheetData>"); if (this.NewXMergeCellInfos.Count != 0) { writer.Write($"<{prefix}mergeCells count=\"{this.NewXMergeCellInfos.Count}\">"); foreach (var cell in this.NewXMergeCellInfos) { writer.Write(cell.ToXmlString(prefix)); } writer.Write($"</{prefix}mergeCells>"); } writer.Write(contents[1]); } }