private static List <TableRowInformation> GetHeaders(EMDocument doc, EMElementOrigin origin, EMElement parent, TransformationData data, int headerOffset, string tableHeader, out bool useRowHeader) { // Add headers // May be multiple lines, may have columns spanning // May also have no header if we are intending the 1st column to be the header var map = new PreprocessedTextLocationMap(); tableHeader = RemoveTrailingWhitespaceAndNewLines(tableHeader, map); List <TableRowInformation> templateHeaderRows = null; useRowHeader = true; if (!String.IsNullOrWhiteSpace(tableHeader)) { templateHeaderRows = new List <TableRowInformation>(); var headerRowOffset = 0; var headerRows = Regex.Split(tableHeader, @"\n"); foreach (var headerRow in headerRows) { var count = 0; var headerColumns = Regex.Matches(headerRow, @"[ ]?([^\|]+)[ ]?([\|]*)"); var row = new TableRowInformation(); foreach (Match headerColumn in headerColumns) { var cellGroup = headerColumn.Groups[1]; var columnSpanLength = 1; if (Regex.Match(headerColumn.Groups[2].Value, @"(\|{2,})").Success) { columnSpanLength = Regex.Match(headerColumn.Groups[2].Value, @"(\|{2,})").Length; } var cell = new TableCellInformation(doc, new EMElementOrigin(headerOffset + map.GetOriginalPosition(headerRowOffset + cellGroup.Index, PositionRounding.Down), cellGroup.Value), parent, data, columnSpanLength, null, true); if (count == 0) { useRowHeader = !Regex.Match(cell.ToString(), @"(\S)").Success; } count++; row.Cells.Add(cell); } headerRowOffset += headerRow.Length + 1; templateHeaderRows.Add(row); } } return(templateHeaderRows); }
private static List <TableRowInformation> GetRows( EMElement parent, TransformationData data, int tableDataOffset, string tableData, string[] alignments, bool useRowHeader, bool hasHeader) { // Add body data var tableRows = new List <TableRowInformation>(); var map = new PreprocessedTextLocationMap(); tableData = RemoveTrailingWhitespaceAndNewLines(tableData, map); var dataRows = Regex.Split(tableData, @"\n"); var rowOffset = 0; for (var i = 0; i < dataRows.Count(); ++i) { var dataRow = dataRows[i]; // Parse table into List of List of CellInformation var count = 0; var dataColumns = Regex.Matches(dataRow, @"([^\|]+)([\|]*)"); var tableRow = new TableRowInformation(); // Check to see if someone has left an empty row incorrectly formatted, which we can fix. if (dataColumns.Count == 0) { var fixedDataRow = dataRow; for (var j = dataRow.Length; j < alignments.Length + 1; ++j) { fixedDataRow += '|'; } fixedDataRow = fixedDataRow.Insert(1, " "); dataColumns = Regex.Matches(fixedDataRow, @"([^\|]+)([\|]*)"); } foreach (Match dataColumn in dataColumns) { int addToOffset; var cell = Normalizer.LeadingWhitespaceRemove(dataColumn.Groups[1].Value, out addToOffset); cell = Normalizer.TrailingWhitespaceRemove(cell); var columnSpanLength = 1; var isRowHeader = (count == 0 && useRowHeader && dataColumns.Count > 1) || (dataColumns.Count == 1 && i == 0 && !hasHeader); if (Regex.Match(dataColumn.Groups[2].Value, @"(\|{2,})").Success) { columnSpanLength = Regex.Match(dataColumn.Groups[2].Value, @"(\|{2,})").Length; } // @UE3 ensure that the index into alignments is not greater than the amount expected. (Users may accidentally add extra || to lines) string alignment = null; if (count >= alignments.Length) { // Report only 1 error per row per run to avoid duplicates if (!tableRow.HasError) { var errorCount = data.ErrorList.Count; tableRow.ErrorId = errorCount; tableRow.HasError = true; data.ErrorList.Add( Markdown.GenerateError( Language.Message( "MoreColumnsThanAllignmentsInOneOfTheTableRowsColumnsIgnored", Markdown.Unescape(dataRows[i])), MessageClass.Error, Markdown.Unescape(dataRows[i]), errorCount, data)); } } else { alignment = alignments[count]; } var cellInformation = (cell.Trim() != "^") ? new TableCellInformation( parent.Document, new EMElementOrigin(tableDataOffset + map.GetOriginalPosition(addToOffset + rowOffset + dataColumn.Groups[1].Index, PositionRounding.Down), cell), parent, data, columnSpanLength, alignment, isRowHeader) : new TableCellInformation(columnSpanLength, alignment, isRowHeader, false, 1, true); tableRow.Cells.Add(cellInformation); // Make parsing table easier later, if ColumnSpan > 1 create a blank column for each over one for (var dummyColumnCount = 1; dummyColumnCount < columnSpanLength; ++dummyColumnCount) { tableRow.Cells.Add(new TableCellInformation(0)); } // @UE3 this was not in original specification, handles correct alignment of a subsequent column after a long column. count += columnSpanLength; } // If count is zero check that someone has just not placed a space in the first column indicating it should be empty. if (count < alignments.Length) { var errorCount = data.ErrorList.Count; tableRow.ErrorId = errorCount; tableRow.HasError = true; data.ErrorList.Add( Markdown.GenerateError( Language.Message( "LessColumnsThanExpectedInOneOfTheTableRowsEmptyCellsInserted", Markdown.Unescape(dataRows[i])), MessageClass.Error, Markdown.Unescape(dataRows[i]), errorCount, data)); } // If count is less than total expected for a rows data add dummy column and raise error for (var dummyColumnCount = count; dummyColumnCount < alignments.Length; ++dummyColumnCount) { tableRow.Cells.Add(new TableCellInformation(1, null, false, true)); } tableRows.Add(tableRow); rowOffset += dataRow.Length + 1; } // Now work out rowspans based on Content and character ^ // Work down rows in columns for (var columnNumber = 0; columnNumber < alignments.Length; ++columnNumber) { var firstNonSpanRow = -1; for (var rowNumber = 0; rowNumber < tableRows.Count; ++rowNumber) { if (tableRows[rowNumber].Cells[columnNumber].IsRowSpanColumn) //Found a rowspan column { if (rowNumber == 0) { var errorCount = data.ErrorList.Count; tableRows[rowNumber].ErrorId = errorCount; tableRows[rowNumber].HasError = true; data.ErrorList.Add( Markdown.GenerateError( Language.Message( "ColumnCannotBeSetToSpanWithSpecialSymbolInTheFirstRowOfATable", dataRows[0]), MessageClass.Error, dataRows[0], errorCount, data)); } else { if (firstNonSpanRow < 0) { //is this the first detected row for this span? firstNonSpanRow = rowNumber - 1; //Row span above this 1 now should include itself tableRows[firstNonSpanRow].Cells[columnNumber].RowSpanCount = 1; } //Increment the Row above first_row detected by 1 tableRows[firstNonSpanRow].Cells[columnNumber].RowSpanCount += 1; } } else if (firstNonSpanRow >= 0) { //This row is not a rowspan but we had one previously so clear for any other rowspans in the column firstNonSpanRow = -1; } } } return(tableRows); }