دمج خلايا الجدول

في بعض الأحيان، تتطلب صفوف معينة في الجدول عنوانا أو كتلا كبيرة من النص تشغل العرض الكامل للجدول. للتصميم المناسب للجدول، يمكن للمستخدم دمج عدة خلايا جدول في خلية واحدة. Aspose.Words يدعم الخلايا المدمجة عند العمل مع جميع تنسيقات الإدخال، بما في ذلك استيراد HTML المحتوى.

كيفية دمج خلايا الجدول

في Aspose.Words، يتم تمثيل الخلايا المدمجة بالخصائص التالية لفئة CellFormat:

  • HorizontalMerge الذي يصف ما إذا كانت الخلية جزءا من دمج أفقي للخلايا
  • VerticalMerge الذي يصف ما إذا كانت الخلية جزءا من دمج عمودي للخلايا

تحدد قيم هذه الخصائص سلوك دمج الخلايا:

  • سيكون للخلية الأولى في سلسلة من الخلايا المدمجة CellMerge.First
  • أي خلايا مدمجة لاحقا سيكون لها CellMerge.Previous
  • الخلية التي لم يتم دمجها سيكون لها CellMerge.None

work-with-merged-cells-aspose-words-java

التحقق مما إذا تم دمج خلية

للتحقق مما إذا كانت الخلية جزءا من سلسلة من الخلايا المدمجة، نتحقق ببساطة من خصائص HorizontalMerge و VerticalMerge.

يوضح مثال الكود التالي كيفية طباعة نوع دمج الخلايا الأفقي والرأسي:

// For complete examples and data files, please go to https://github.com/aspose-words/Aspose.Words-for-Java.git.
Document doc = new Document(getMyDir() + "Table with merged cells.docx");
Table table = (Table) doc.getChild(NodeType.TABLE, 0, true);
for (Row row : (Iterable<Row>) table.getRows())
{
for (Cell cell : (Iterable<Cell>) row.getCells())
{
System.out.println(printCellMergeType(cell));
}
}

دمج خلايا الجدول عند استخدام DocumentBuilder

لدمج الخلايا في جدول تم إنشاؤه باستخدام DocumentBuilder، تحتاج إلى تعيين نوع الدمج المناسب لكل خلية حيث يتوقع الدمج - أولا CellMerge.First ثم CellMerge.Previous.

أيضا، يجب أن تتذكر مسح إعداد الدمج لتلك الخلايا حيث لا يلزم الدمج-يمكن القيام بذلك عن طريق تعيين أول خلية غير دمج إلى CellMerge.None. إذا لم يتم ذلك، سيتم دمج جميع الخلايا في الجدول.

يوضح مثال التعليمات البرمجية التالية كيفية إنشاء جدول مع صفين حيث يتم دمج الخلايا في الصف الأول أفقيا:

// For complete examples and data files, please go to https://github.com/aspose-words/Aspose.Words-for-Java.git.
Document doc = new Document();
DocumentBuilder builder = new DocumentBuilder(doc);
builder.insertCell();
builder.getCellFormat().setHorizontalMerge(CellMerge.FIRST);
builder.write("Text in merged cells.");
builder.insertCell();
// This cell is merged to the previous and should be empty.
builder.getCellFormat().setHorizontalMerge(CellMerge.PREVIOUS);
builder.endRow();
builder.insertCell();
builder.getCellFormat().setHorizontalMerge(CellMerge.NONE);
builder.write("Text in one cell.");
builder.insertCell();
builder.write("Text in another cell.");
builder.endRow();
builder.endTable();
doc.save(getArtifactsDir() + "WorkingWithTables.HorizontalMerge.docx");

يوضح مثال التعليمات البرمجية التالية كيفية إنشاء جدول عمودين حيث يتم دمج الخلايا في العمود الأول عموديا:

// For complete examples and data files, please go to https://github.com/aspose-words/Aspose.Words-for-Java.git.
Document doc = new Document();
DocumentBuilder builder = new DocumentBuilder(doc);
builder.insertCell();
builder.getCellFormat().setVerticalMerge(CellMerge.FIRST);
builder.write("Text in merged cells.");
builder.insertCell();
builder.getCellFormat().setVerticalMerge(CellMerge.NONE);
builder.write("Text in one cell");
builder.endRow();
builder.insertCell();
// This cell is vertically merged to the cell above and should be empty.
builder.getCellFormat().setVerticalMerge(CellMerge.PREVIOUS);
builder.insertCell();
builder.getCellFormat().setVerticalMerge(CellMerge.NONE);
builder.write("Text in another cell");
builder.endRow();
builder.endTable();
doc.save(getArtifactsDir() + "WorkingWithTables.VerticalMerge.docx");

دمج خلايا الجدول في حالات أخرى

في المواقف الأخرى التي لا يتم فيها استخدام DocumentBuilder، كما هو الحال في جدول موجود، قد لا يكون دمج الخلايا بالطريقة السابقة بهذه السهولة. بدلا من ذلك، يمكننا التفاف العمليات الأساسية المتضمنة في تطبيق خصائص الدمج على الخلايا بطريقة تجعل المهمة أسهل بكثير. تشبه هذه الطريقة طريقة أتمتة الدمج، والتي تسمى لدمج نطاق من الخلايا في جدول.

سيقوم الرمز أدناه بدمج خلايا الجدول في النطاق المحدد، بدءا من الخلية المحددة وتنتهي عند الخلية النهائية. في هذه الحالة، يمكن أن يمتد النطاق إلى عدة صفوف أو أعمدة:

// For complete examples and data files, please go to https://github.com/aspose-words/Aspose.Words-for-Java.git.
void mergeCells(Cell startCell, Cell endCell)
{
Table parentTable = startCell.getParentRow().getParentTable();
// Find the row and cell indices for the start and end cell.
Point startCellPos = new Point(startCell.getParentRow().indexOf(startCell),
parentTable.indexOf(startCell.getParentRow()));
Point endCellPos = new Point(endCell.getParentRow().indexOf(endCell), parentTable.indexOf(endCell.getParentRow()));
// Create a range of cells to be merged based on these indices.
// Inverse each index if the end cell is before the start cell.
Rectangle mergeRange = new Rectangle(Math.min(startCellPos.x, endCellPos.y),
Math.min(startCellPos.y, endCellPos.y),
Math.abs(endCellPos.x - startCellPos.x) + 1, Math.abs(endCellPos.y - startCellPos.y) + 1);
for (Row row : parentTable.getRows())
{
for (Cell cell : row.getCells())
{
Point currentPos = new Point(row.indexOf(cell), parentTable.indexOf(row));
// Check if the current cell is inside our merge range, then merge it.
if (mergeRange.contains(currentPos))
{
cell.getCellFormat().setHorizontalMerge(currentPos.x == mergeRange.getX() ? CellMerge.FIRST : CellMerge.PREVIOUS);
cell.getCellFormat().setVerticalMerge(currentPos.y == mergeRange.getY() ? CellMerge.FIRST : CellMerge.PREVIOUS);
}
}
}
}

يوضح مثال الكود التالي كيفية دمج نطاق من الخلايا بين خليتين محددتين:

// For complete examples and data files, please go to https://github.com/aspose-words/Aspose.Words-for-Java.git.
Document doc = new Document(getMyDir() + "Table with merged cells.docx");
Table table = doc.getFirstSection().getBody().getTables().get(0);
// We want to merge the range of cells found inbetween these two cells.
Cell cellStartRange = table.getRows().get(0).getCells().get(0);
Cell cellEndRange = table.getRows().get(1).getCells().get(1);
// Merge all the cells between the two specified cells into one.
mergeCells(cellStartRange, cellEndRange);
doc.save(getArtifactsDir() + "WorkingWithTables.MergeCellRange.docx");

الخلايا المدمجة الرأسية والأفقية في HTML جدول

كما قلنا في مقالات سابقة، الجدول في Microsoft Word عبارة عن مجموعة من الصفوف المستقلة. يحتوي كل صف على مجموعة من الخلايا المستقلة عن خلايا الصفوف الأخرى. وهكذا، في الجدول Microsoft Word لا يوجد كائن مثل “عمود”، و" العمود 1 “هو شيء مثل"مجموعة من الخلايا 1 من كل صف في الجدول”. هذا يسمح للمستخدمين أن يكون الجدول الذي، على سبيل المثال، الصف 1 يتكون من خليتين – 2 سم و 1 سم، والصف 2 يتكون من خليتين مختلفتين – 1 سم و 2 سم واسعة. و Aspose.Words يدعم هذا المفهوم من الجداول.

يحتوي الجدول في HTML على بنية مختلفة بشكل أساسي: يحتوي كل صف على نفس عدد الخلايا و (من المهم للمهمة) لكل خلية عرض العمود المقابل، وهو نفسه لجميع الخلايا في عمود واحد. حتى إذا HorizontalMerge و VerticalMerge إرجاع قيمة غير صحيحة، استخدم المثال التعليمات البرمجية التالية:

// For complete examples and data files, please go to https://github.com/aspose-words/Aspose.Words-for-Java.git.
Document doc = new Document(getMyDir() + "Table with merged cells.docx");
SpanVisitor visitor = new SpanVisitor(doc);
doc.accept(visitor);
// For complete examples and data files, please go to https://github.com/aspose-words/Aspose.Words-for-Java.git.
/// <summary>
/// Helper class that contains collection of rowinfo for each row.
/// </summary>
public static class TableInfo
{
public ArrayList<RowInfo> getRows() { return mRows; }
private ArrayList<RowInfo> mRows = new ArrayList<>();
}
/// <summary>
/// Helper class that contains collection of cellinfo for each cell.
/// </summary>
public static class RowInfo
{
public ArrayList<CellInfo> getCells() { return mCells; };
private ArrayList<CellInfo> mCells = new ArrayList<>();
}
/// <summary>
/// Helper class that contains info about cell. currently here is only colspan and rowspan.
/// </summary>
public static class CellInfo
{
public CellInfo(int colSpan, int rowSpan)
{
mColSpan = colSpan;
mRowSpan = rowSpan;
}
public int getColSpan() { return mColSpan; };
private int mColSpan;
public int getRowSpan() { return mRowSpan; };
private int mRowSpan;
}
public static class SpanVisitor extends DocumentVisitor
{
/// <summary>
/// Creates new SpanVisitor instance.
/// </summary>
/// <param name="doc">
/// Is document which we should parse.
/// </param>
public SpanVisitor(Document doc) throws Exception {
mWordTables = doc.getChildNodes(NodeType.TABLE, true);
// We will parse HTML to determine the rowspan and colspan of each cell.
ByteArrayOutputStream htmlStream = new ByteArrayOutputStream();
HtmlSaveOptions options = new HtmlSaveOptions();
{
options.setImagesFolder(System.getProperty("java.io.tmpdir"));
}
doc.save(htmlStream, options);
// Load HTML into the XML document.
org.jsoup.nodes.Document document = Jsoup.parse(htmlStream.toString());
// Get collection of tables in the HTML document.
Elements tables = document.getElementsByTag("table");
for (Element table : tables) {
TableInfo tableInf = new TableInfo();
// Get collection of rows in the table.
Elements rows = table.getElementsByTag("tr");
for (Element row : rows) {
RowInfo rowInf = new RowInfo();
// Get collection of cells.
Elements cells = row.getElementsByTag("td");
for (Element cell : cells) {
// Determine row span and colspan of the current cell.
String colSpanAttr = cell.attributes().get("colspan");
String rowSpanAttr = cell.attributes().get("rowspan");
int colSpan = StringUtils.isNotBlank(colSpanAttr) ? Integer.parseInt(colSpanAttr) : 0;
int rowSpan = StringUtils.isNotBlank(rowSpanAttr) ? Integer.parseInt(rowSpanAttr) : 0;
CellInfo cellInf = new CellInfo(colSpan, rowSpan);
rowInf.getCells().add(cellInf);
}
tableInf.getRows().add(rowInf);
}
mTables.add(tableInf);
}
}
public int visitCellStart(Cell cell)
{
int tabIdx = mWordTables.indexOf(cell.getParentRow().getParentTable());
int rowIdx = cell.getParentRow().getParentTable().indexOf(cell.getParentRow());
int cellIdx = cell.getParentRow().indexOf(cell);
int colSpan = 0;
int rowSpan = 0;
if (tabIdx < mTables.size() &&
rowIdx < mTables.get(tabIdx).getRows().size() &&
cellIdx < mTables.get(tabIdx).getRows().get(rowIdx).getCells().size())
{
colSpan = mTables.get(tabIdx).getRows().get(rowIdx).getCells().get(cellIdx).getColSpan();
rowSpan = mTables.get(tabIdx).getRows().get(rowIdx).getCells().get(cellIdx).getRowSpan();
}
System.out.println(MessageFormat.format("{0}.{1}.{2} colspan={3}\t rowspan={4}", tabIdx, rowIdx, cellIdx, colSpan, rowSpan));
return VisitorAction.CONTINUE;
}
private ArrayList<TableInfo> mTables = new ArrayList<>();
private NodeCollection mWordTables;
}

تحويل إلى خلايا مدمجة أفقيا

في بعض الأحيان لا يمكن اكتشاف الخلايا التي يتم دمجها لأن بعض الإصدارات الأحدث من Microsoft Word لم تعد تستخدم علامات الدمج عند دمج الخلايا أفقيا. ولكن بالنسبة للحالات التي يتم فيها دمج الخلايا في خلية أفقيا بعرضها باستخدام علامات الدمج ،Aspose.Words يوفر طريقة ConvertToHorizontallyMergedCells لتحويل الخلايا. تقوم هذه الطريقة ببساطة بتحويل الجدول وإضافة خلايا جديدة حسب الحاجة.

يوضح مثال الكود التالي الطريقة المذكورة أعلاه قيد التشغيل:

// For complete examples and data files, please go to https://github.com/aspose-words/Aspose.Words-for-Java.git.
Document doc = new Document(getMyDir() + "Table with merged cells.docx");
Table table = doc.getFirstSection().getBody().getTables().get(0);
// Now merged cells have appropriate merge flags.
table.convertToHorizontallyMergedCells();