Вложенные Mail Merge с регионами

В некоторых случаях вам может потребоваться использовать вложенные Mail Merge области. Вложенное слияние - это функция, которая позволяет объединять иерархические данные из вашего источника данных в шаблон слияния для упрощения заполнения вашего документа. По сути, иерархические данные представлены в виде набора элементов данных, а иерархические связи описывают, как элементы данных связаны друг с другом (один элемент данных является родительским для другого).

Aspose.Words позволяет выполнить операцию Mail Merge с вложенными областями. Вы можете использовать эту функцию, если у вас есть источник данных, организованный в виде древовидной структуры, и вы хотите выполнить операцию Mail Merge для заполнения шаблона иерархическими данными.

Что такое вложенный Mail Merge

Область Mail Merge называется вложенной, если у вас есть две или более области mail merge, одна из которых находится внутри другой в иерархической форме. Обратите внимание, что каждая область содержит данные из одной таблицы.

Наиболее распространенным примером вложенного Mail Merge является заказ, содержащий несколько элементов, в котором вам нужно связать множество таблиц данных и представить информацию в виде шаблона.

На рисунке ниже показаны две вложенные области, где область Order Mail Merge является родительской для области Item mail merge.

nested_mail_merge_with_regions

Как обработать Mail Merge с вложенными областями

Данные, которые будут объединены в шаблон, могут быть получены из различных источников, в основном из реляционных баз данных или документов XML. В нашем примере мы будем использовать SQLite база данных для хранения наших данных и загрузки их с помощью пользовательской реализации источника данных.

На рисунке ниже показано, как данные из таблицы Order, передаваемые во вложенные области слияния, будут связаны с таблицей Item, а также выходные данные, сгенерированные во время операции слияния.

mail_merge_with_nested_regions

Как вы можете видеть из выходного документа, каждый заказ из таблицы Order вставляется в шаблон объединения со всеми связанными с заказом позициями из таблицы Item. Следующий заказ будет вставляться вместе со своими позициями до тех пор, пока не будут перечислены все заказы и позиции. Порядок вложения Mail Merge регионов в шаблон должен соответствовать соотношениям данных между таблицами в источнике данных.

Как создать связи с данными из пользовательского источника данных

Реализуйте интерфейс IMailMergeDataSource для создания связей в структуре “родитель-потомок” вашего пользовательского источника данных. Используйте метод GetChildDataSource, чтобы вернуть соответствующие дочерние данные текущей родительской записи.

В следующем примере кода показано, как сгенерировать счет-фактуру, используя вложенные 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;
};