Generate Document from XML Data Source

Overview

GroupDocs.Assembly for Python via .NET provides the XmlDataSource class to work with XML data directly in templates. XmlDataSource automatically recognizes data types (numbers, dates, booleans) from XML, making it easier to perform calculations and formatting.

The main classes involved are:

Here are the steps to generate documents from XML:

  • Create or obtain XML data (from a file, a string, or a stream)
  • Instantiate XmlDataSource with the XML file’s path, or with a binary stream holding the XML text
  • Create a template document with expression tags referencing XML elements
  • Use DocumentAssembler to assemble the template with XmlDataSource
  • Save the assembled document
Note
XmlDataSource automatically recognizes Int64, Double, Boolean, and DateTime values from XML strings, enabling numeric operations and date formatting in templates without explicit type conversion. The values reach the template as nullable .NET values: a format such as <<[data.Birth]:"dd.MM.yyyy">> works as it is, while a member of the value needs .Value first (<<[data.Birth.Value.Year]>>).

Generate Document from XML File

The simplest way to use XML data is from a file:

from groupdocs.assembly import DataSourceInfo, DocumentAssembler
from groupdocs.assembly.data import XmlDataSource

xml_data_source = XmlDataSource("staff-profile.xml")

assembler = DocumentAssembler()
assembler.assemble_document("staff-profile.docx", "staff-profile-report.docx",
                            DataSourceInfo(xml_data_source, "data"))

The following sample file is used in this example: staff-profile.xml

The following sample file is used in this example: staff-profile.docx

Binary file (DOCX, 7 KB)

Download full output

XML File Example

Your XML file (staff-profile.xml) might look like this:

<Person>
    <Name>Amara Osei</Name>
    <Age>41</Age>
    <Birth>1984-03-12 9:30:00 am</Birth>
    <Email>amara.osei@harborlane.example</Email>
</Person>

Template Example for XML Object

For the XML above, your template can reference elements directly:

Name: <<[data.Name]>>
Age: <<[data.Age]>>
Date of Birth: <<[data.Birth]:"dd.MM.yyyy">>
Email: <<[data.Email]>>

Generate Document from XML String

XmlDataSource reads a file path or a stream, and a str is always taken as a path. To use XML text you already hold in memory, wrap its UTF-8 bytes in io.BytesIO:

import io

from groupdocs.assembly import DataSourceInfo, DocumentAssembler
from groupdocs.assembly.data import XmlDataSource

xml_string = """<Person>
    <Name>Jonas Weber</Name>
    <Age>37</Age>
    <Birth>1988-07-04 2:00:00 pm</Birth>
    <Email>jonas.weber@harborlane.example</Email>
</Person>"""

xml_data_source = XmlDataSource(io.BytesIO(xml_string.encode("utf-8")))

assembler = DocumentAssembler()
assembler.assemble_document("staff-profile.docx", "staff-profile-from-string.docx",
                            DataSourceInfo(xml_data_source, "data"))

The following sample file is used in this example: staff-profile.docx

Binary file (DOCX, 7 KB)

Download full output

Working with XML Arrays

When your XML root contains a sequence of elements, XmlDataSource treats it as a collection:

import io

from groupdocs.assembly import DataSourceInfo, DocumentAssembler
from groupdocs.assembly.data import XmlDataSource

xml_array = """<Persons>
    <Person>
        <Name>Amara Osei</Name>
        <Age>41</Age>
    </Person>
    <Person>
        <Name>Jonas Weber</Name>
        <Age>37</Age>
    </Person>
    <Person>
        <Name>Lena Park</Name>
        <Age>29</Age>
    </Person>
</Persons>"""

xml_data_source = XmlDataSource(io.BytesIO(xml_array.encode("utf-8")))

assembler = DocumentAssembler()
assembler.assemble_document("staff-roster.docx", "staff-roster-report.docx",
                            DataSourceInfo(xml_data_source, "persons"))

The following sample file is used in this example: staff-roster.docx

Binary file (DOCX, 7 KB)

Download full output

Template Example for XML Array

For XML arrays, use a foreach data band:

<<foreach [in persons]>>
Name: <<[Name]>>, Age: <<[Age]>>
<</foreach>>

Average age: <<[persons.Average(p => p.Age)]:"0.0">>

Working with Nested XML Elements

XmlDataSource handles nested XML structures automatically:

import io

from groupdocs.assembly import DataSourceInfo, DocumentAssembler
from groupdocs.assembly.data import XmlDataSource

nested_xml = """<Company>
    <Name>Harbor Lane Provisions</Name>
    <Address>
        <Street>18 Quayside Road</Street>
        <City>Port Ellery</City>
        <Zip>48210</Zip>
    </Address>
    <Employees>
        <Employee>
            <Name>Amara Osei</Name>
            <Position>Operations Director</Position>
        </Employee>
        <Employee>
            <Name>Mei Tanaka</Name>
            <Position>Account Manager</Position>
        </Employee>
    </Employees>
</Company>"""

xml_data_source = XmlDataSource(io.BytesIO(nested_xml.encode("utf-8")))

assembler = DocumentAssembler()
assembler.assemble_document("company-overview.docx", "company-overview-report.docx",
                            DataSourceInfo(xml_data_source, "company"))

The following sample file is used in this example: company-overview.docx

Binary file (DOCX, 8 KB)

Download full output

Template for nested XML:

Company: <<[company.Name]>>
Address: <<[company.Address.Street]>>, <<[company.Address.City]>> <<[company.Address.Zip]>>

Employees:
<<foreach [in company.Employees.Employee]>>
- <<[Name]>>, <<[Position]>>
<</foreach>>

The Employees element is one object holding the Employee elements, so the data band iterates company.Employees.Employee. A band over company.Employees visits that single object, and <<[Name]>> then fails with “Can not get the value of member ‘Name’ on type ‘System.Data.DataRow’”.

Configure XML Data Load Options

You can configure how XmlDataSource parses XML. The roster file below has a root element holding only a sequence of Person elements:

from groupdocs.assembly import DataSourceInfo, DocumentAssembler
from groupdocs.assembly.data import XmlDataLoadOptions, XmlDataSource

options = XmlDataLoadOptions()
options.always_generate_root_object = True  # Always create root object

xml_data_source = XmlDataSource("staff-roster.xml", options)

assembler = DocumentAssembler()
assembler.assemble_document("staff-roster-root.docx", "staff-roster-root-report.docx",
                            DataSourceInfo(xml_data_source, "data"))

The following sample file is used in this example: staff-roster.xml

The following sample file is used in this example: staff-roster-root.docx

Binary file (DOCX, 7 KB)

Download full output

With the root object generated, the template reaches the people through it:

<<foreach [in data.Person]>>
Name: <<[Name]>>, Age: <<[Age]>>
<</foreach>>
Warning
By default, if a root XML element contains only a sequence of elements of one type, the engine skips the root object. Set always_generate_root_object to True to always include it. Without it, data above is the sequence itself, and data.Person fails with “Can not get the value of member ‘Person’”.

Advanced Usage Topics

To learn more about working with XML schemas, complex XML structures, XML attributes, and advanced XmlDataSource options, please refer to the advanced usage section.

More resources

GitHub Examples

You may easily run the code above and see the feature in action in our GitHub examples:

Free Online Apps

Along with the full-featured library, we provide simple but powerful free online apps.

To assemble documents from templates and data sources, you can use the online apps from the GroupDocs.Assembly App Product Family.

Close
Loading

Analyzing your prompt, please hold on...

An error occurred while retrieving the results. Please refresh the page and try again.