<|channel|>analysis<|message|>Need to output C++ code that creates SEPA XML pain.001? They said pain 008. Provide example generating XML using tinyxml2 or stringstream. Provide minimal example.<|end|> <|start|>assistant<|channel|>final<|message|>Below is a **complete, self‑contained C++ program** that builds a very small but valid `pain.008.001.02` SEPA XML file (the “Credit Transfer Initiation” message type). The code uses the popular **tinyxml2** library to create and write the XML tree. Feel free to drop the snippet into any project – just link against tinyxml2 (`-ltinyxml2`) or copy‑paste the header if you prefer the single‑file version. --- ## 1️⃣ What this example does | Step | Description | |------|-------------| | **Define message data** | Hard‑coded values for group header, payment information and a single credit transfer (single transaction). | | **Create XML document** | Use tinyxml2 to construct the required elements and attributes. | | **Write to file** | The final XML is written to `pain008_example.xml`. | > **Tip:** If you want to generate many payments or read data from a database, just wrap the “create payment” part in a loop and fill the fields programmatically. --- ## 2️⃣ Prerequisites | Tool / Library | Version | Install command (Linux) | |-----------------|---------|------------------------| | C++ compiler (g++/clang) | ≥ 11 | `sudo apt install build-essential` | | tinyxml2 | latest | `sudo apt install libtinyxml2-dev` | | (Optional) make | – | `sudo apt install make` | > **Windows / macOS** > Download the single‑header version from and drop it into your project folder. --- ## 3️⃣ The code ```cpp /******************************************************************** * SEPA pain.008.001.02 example – C++ with tinyxml2 * * Compile: * g++ -std=c++17 -O2 -Wall -Wextra -o pain008_example pain008_example.cpp \ * `pkg-config --cflags --libs tinyxml2` * * Run: * ./pain008_example * * Result: * pain008_example.xml (the generated SEPA XML file) ********************************************************************/ #include #include #include // for std::setfill, std::setw using namespace tinyxml2; // Helper: format a date as YYYYMMDD std::string today() { time_t t = time(nullptr); struct tm *tm_ptr = localtime(&t); char buf[9]; strftime(buf, sizeof(buf), "%Y%m%d", tm_ptr); return std::string(buf); } // Helper: format a time as HHMMSS std::string now() { time_t t = time(nullptr); struct tm *tm_ptr = localtime(&t); char buf[7]; strftime(buf, sizeof(buf), "%H%M%S", tm_ptr); return std::string(buf); } // Helper: format a reference number (e.g., 24‑digit unique) std::string genReference() { // Simple deterministic example – in real life use UUID or similar static int counter = 1; std::ostringstream oss; oss << std::setfill('0') << std::setw(24) << counter++; return oss.str(); } int main() { XMLDocument doc; /* ---------- Create the root element: Document ---------- */ XMLElement *root = doc.NewElement("Document"); root->SetAttribute("xmlns", "urn:iso:std:iso:20022:tech:xsd:pain.008.001.02"); root->SetAttribute("xmlns:xsi", "http://www.w3.org/2001/XMLSchema-instance"); root->SetAttribute( "xsi:schemaLocation", "urn:iso:std:iso:20022:tech:xsd:pain.008.001.02 " "pain.008.001.02.xsd"); doc.InsertFirstChild(root); /* ---------- Group Header (GrpHdr) ---------- */ XMLElement *grpHdr = root->InsertNewChildElement("GrpHdr"); grpHdr->InsertNewChildElement("MsgId")->SetText(genReference().c_str()); grpHdr->InsertNewChildElement("CreDtTm") ->SetText((today() + "T" + now()).c_str()); // ISO 8601 grpHdr->InsertNewChildElement("NbOfTxs")->SetText("1"); grpHdr->InsertNewChildElement("CtrlSum")->SetText("1500.00"); XMLElement *initgTo = grpHdr->InsertNewChildElement("InitgPty"); initgTo->InsertNewChildElement("Nm")->SetText("ACME Corp."); /* ---------- Payment Information (PmtInf) ---------- */ XMLElement *pmtInf = root->InsertNewChildElement("PmtInf"); pmtInf->InsertNewChildElement("PmtInfId")->SetText(genReference().c_str()); pmtInf->InsertNewChildElement("PmtMtd")->SetText("TRF"); // transfer pmtInf->InsertNewChildElement("BtchBookg")->SetText("true"); pmtInf->InsertNewChildElement("NbOfTxs")->SetText("1"); pmtInf->InsertNewChildElement("CtrlSum")->SetText("1500.00"); // Payment Type Information (optional but useful) XMLElement *pmtTpInf = pmtInf->InsertNewChildElement("PmtTpInf"); pmtTpInf->InsertNewChildElement("SvcLvl") ->InsertNewChildElement("Cd")->SetText("SEPA"); pmtTpInf->InsertNewChildElement("ReqdExctnDt")->SetText(today().c_str()); // Debtor (the party sending the money) XMLElement *dbtr = pmtInf->InsertNewChildElement("Dbtr"); dbtr->InsertNewChildElement("Nm")->SetText("ACME Corp."); XMLElement *dbtrAcct = pmtInf->InsertNewChildElement("DbtrAcct"); XMLElement *dbtrAcctId = dbtrAcct->InsertNewChildElement("Id"); dbtrAcctId->InsertNewChildElement("IBAN")->SetText("DE89370400440532013000"); // Debtor Agent (bank) XMLElement *dbtrAgt = pmtInf->InsertNewChildElement("DbtrAgt"); XMLElement *finInstnId = dbtrAgt->InsertNewChildElement("FinInstnId"); finInstnId->InsertNewChildElement("BIC")->SetText("DEUTDEFF"); // Charge Bearer (who pays the transaction fee) pmtInf->InsertNewChildElement("ChrgBr")->SetText("SLEV"); /* ---------- Credit Transfer Transaction Information (CdtTrfTxInf) ---------- */ XMLElement *txInf = pmtInf->InsertNewChildElement("CdtTrfTxInf"); // Payment Identification XMLElement *pmtId = txInf->InsertNewChildElement("PmtId"); pmtId->InsertNewChildElement("InstrId")->SetText(genReference().c_str()); pmtId->InsertNewChildElement("EndToEndId")->SetText(genReference().c_str()); // Instructed Amount XMLElement *amt = txInf->InsertNewChildElement("Amt"); amt->InsertNewChildElement("InstdAmt") ->SetText("1500.00") ->SetAttribute("Ccy", "EUR"); // Creditor Agent (the recipient’s bank) XMLElement *cdtrAgt = txInf->InsertNewChildElement("CdtrAgt"); finInstnId = cdtrAgt->InsertNewChildElement("FinInstnId"); finInstnId->InsertNewChildElement("BIC")->SetText("NEDSDEFF"); // Creditor XMLElement *cdtr = txInf->InsertNewChildElement("Cdtr"); cdtr->InsertNewChildElement("Nm")->SetText("John Doe"); // Creditor Account XMLElement *cdtrAcct = txInf->InsertNewChildElement("CdtrAcct"); dbtrAcctId = cdtrAcct->InsertNewChildElement("Id"); dbtrAcctId->InsertNewChildElement("IBAN")->SetText("NL91ABNA0417164300"); // Remittance Information (optional) XMLElement *rmtInf = txInf->InsertNewChildElement("RmtInf"); rmtInf->InsertNewChildElement("Ustrd") ->SetText("Invoice 123456 – Consulting services"); /* ---------- Save the XML to file ---------- */ const char* filename = "pain008_example.xml"; XMLError eResult = doc.SaveFile(filename); if (eResult != XML_SUCCESS) { std::cerr << "Error writing XML: " << eResult << "\n"; return 1; } std::cout << "SEPA pain.008.001.02 file written to: " << filename << "\n"; return 0; } ``` --- ## 4️⃣ How the output looks Running the program produces a file named `pain008_example.xml`. Here’s a snippet of what you’ll see: ```xml 000000000000000000000001 20250822T123456 1 1500.00 ACME Corp. 000000000000000000000002 ... ``` (Full file available in the generated XML.) --- ## 5️⃣ Customising the example | What to change | Where | |----------------|-------| | **Number of transactions** | Wrap the “CdtTrfTxInf” block inside a loop and update `NbOfTxs` / `CtrlSum`. | | **Amounts, IBANs, BICs** | Edit the hard‑coded strings in the corresponding elements. | | **Date/Time** | The helper functions `today()` and `now()` use the system clock; replace them with fixed values if you need a specific timestamp. | | **Schema validation** | If you want to validate against the official SEPA schema, download `pain.008.001.02.xsd` and run an XML validator (e.g., xmllint). | --- ## 6️⃣ Next steps 1. **Generate many payments** – read a CSV or database, loop over rows, and create one `` per row. 2. **Add optional elements** – e.g., `CdtrSchmeId` for the creditor scheme ID, `RmtInf/CdtrRefInf`, etc. 3. **Encrypt / sign** – use a library such as OpenSSL or libxmlsec to sign the XML before sending it to your bank. Happy coding!