Mail Merge с регионами
Вы можете создавать различные области в своем шаблоне, чтобы иметь специальные области, которые вы можете просто заполнить своими данными. Используйте Mail Merge с регионами, если вы хотите вставлять таблицы, строки с повторяющимися данными, чтобы ваши документы динамически расширялись, указав эти области в вашем шаблоне.
Вы можете создавать вложенные (дочерние) области, а также объединять области. Основное преимущество использования этого типа заключается в динамическом увеличении частей внутри документа. Более подробную информацию смотрите в следующей статье “Вложенные Mail Merge области с областями”.
Как выполнить Mail Merge с регионами
Область Mail Merge - это определенная часть документа, имеющая начальную и конечную точки. Обе точки представлены в виде Mail Merge полей с определенными именами “TableStart:XXX” и “TableEnd:XXX”. Все содержимое, включенное в область mail merge, будет автоматически повторяться для каждой записи в источнике данных.
Aspose.Words позволяет выполнять Mail Merge с регионами, используя один из методов ExecuteWithRegions, которые принимают IMailMergeDataSource пользовательский источник данных.
В следующем примере кода показано, как выполнить Mail Merge с регионами из базы данных sqlite с помощью SQLiteCpp:
// For complete examples and data files, please go to https://github.com/aspose-words/Aspose.Words-for-C.git. | |
void NestedMailMerge() | |
{ | |
auto doc = MakeObject<Document>(); | |
auto builder = MakeObject<DocumentBuilder>(doc); | |
builder->InsertField(u" MERGEFIELD TableStart:Customers"); | |
builder->Write(u"Full name:\t"); | |
builder->InsertField(u" MERGEFIELD FullName "); | |
builder->Write(u"\nAddress:\t"); | |
builder->InsertField(u" MERGEFIELD Address "); | |
builder->Write(u"\nOrders:\n"); | |
builder->InsertField(u" MERGEFIELD TableStart:Orders"); | |
builder->Write(u"\tItem name:\t"); | |
builder->InsertField(u" MERGEFIELD ItemName "); | |
builder->Write(u"\n\tQuantity:\t"); | |
builder->InsertField(u" MERGEFIELD Quantity "); | |
builder->InsertParagraph(); | |
builder->InsertField(u" MERGEFIELD TableEnd:Orders"); | |
builder->InsertField(u" MERGEFIELD TableEnd:Customers"); | |
SQLite::Database database((std::string)(DatabaseDir + u"customers.db3")); | |
// To be able to mail merge from your data source, | |
// it must be wrapped into an object that implements the IMailMergeDataSource interface. | |
auto customersDataSource = MakeObject<NestedMailMergeCustom::CustomersDataSource>(database); | |
doc->get_MailMerge()->ExecuteWithRegions(customersDataSource); | |
doc->Save(ArtifactsDir + u"NestedMailMergeCustom.CustomMailMerge.docx"); | |
} | |
class OrdersDataSource : public MailMerging::IMailMergeDataSource | |
{ | |
public: | |
OrdersDataSource(SQLite::Database& database, int32_t id) | |
: mQuery(database, "SELECT ItemName, Quantity FROM Orders WHERE CustomerId = ?") | |
{ | |
mQuery.bind(1, id); | |
} | |
String get_TableName() override | |
{ | |
return u"Orders"; | |
} | |
bool GetValue(String fieldName, SharedPtr<Object>& fieldValue) override | |
{ | |
if (fieldName == u"ItemName") | |
{ | |
fieldValue = System::ObjectExt::Box<String>(String::FromUtf8(mQuery.getColumn(0).getString())); | |
return true; | |
} | |
if (fieldName == u"Quantity") | |
{ | |
fieldValue = System::ObjectExt::Box<int32_t>(mQuery.getColumn(1).getInt()); | |
return true; | |
} | |
fieldValue.reset(); | |
return false; | |
} | |
bool MoveNext() override | |
{ | |
return mQuery.executeStep(); | |
} | |
SharedPtr<IMailMergeDataSource> GetChildDataSource(String tableName) override | |
{ | |
return nullptr; | |
} | |
private: | |
SQLite::Statement mQuery; | |
}; | |
class CustomersDataSource : public MailMerging::IMailMergeDataSource | |
{ | |
public: | |
CustomersDataSource(SQLite::Database& database) | |
: mDatabase{ database } | |
, mQuery{ mDatabase, "SELECT * FROM Customers" } | |
{ | |
} | |
String get_TableName() override | |
{ | |
return u"Customers"; | |
} | |
bool GetValue(String fieldName, SharedPtr<Object>& fieldValue) override | |
{ | |
if (fieldName == u"FullName") | |
{ | |
fieldValue = System::ObjectExt::Box<String>(String::FromUtf8(mQuery.getColumn(1).getString())); | |
return true; | |
} | |
if (fieldName == u"Address") | |
{ | |
fieldValue = System::ObjectExt::Box<String>(String::FromUtf8(mQuery.getColumn(2).getString())); | |
return true; | |
} | |
fieldValue.reset(); | |
return false; | |
} | |
bool MoveNext() override | |
{ | |
return mQuery.executeStep(); | |
} | |
SharedPtr<IMailMergeDataSource> GetChildDataSource(String tableName) override | |
{ | |
if (tableName == u"Orders") | |
{ | |
return MakeObject<OrdersDataSource>(mDatabase, mQuery.getColumn(0).getInt()); | |
} | |
return nullptr; | |
} | |
private: | |
SQLite::Database& mDatabase; | |
SQLite::Statement mQuery; | |
}; |
Вы можете заметить разницу между документами перед выполнением Mail Merge с регионами:

И после выполнения Mail Merge с регионами:

Ограничения Mail Merge для регионов
Есть несколько важных моментов, которые необходимо учитывать при выполнении Mail Merge с регионами:
- Начальная точка TableStart:Orders и конечная точка TableEnd:Orders должны находиться в одной строке или ячейке. Например, если область объединения начинается в ячейке таблицы, то область объединения должна заканчиваться в той же строке, что и первая ячейка. Имя объединяемого поля должно совпадать с именем столбца в вашем DataTable. Если вы не укажете сопоставленные поля, Mail Merge с регионами не будет выполнено для любого объединяемого поля, имя которого отличается от имени столбца.
- Aspose.Words для C++ поддерживает только источники данных на основе IMailMergeDataSource и IMailMergeDataSourceRoot. В отличие от .NET и Java, C++ не имеет общепринятой кроссплатформенности API для работы с базами данных (например, ADODB, ODBC или JDBC). Чтобы работать с определенным источником данных, вы должны реализовать интерфейс IMailMergeDataSource или IMailMergeDataSourceRoot.
Если одно из этих правил будет нарушено, вы получите неожиданные результаты или может возникнуть исключение.