Skip to content

Writing XML Documents

The XML Writer builds its document from XPath expressions: an Initial XPath, a Transaction Type XPath per transaction, and an XPath and Attribute per field. The recipes below are the four things that expression syntax is asked to do that are not obvious from the field grid.

  1. Which XPath names the repeating node
  2. Writing attributes
  3. Attribute paths
  4. Using a template document

The integration

All four are photographed against DOCSWRITE, whose CSV Reader reads three orders out of orders-ordered.csv as Order, OrderLine and Charge, and whose Xml Writer targets a file:

The Xml Writer Setup tab, Target section. Target is File, File System Windows, File Path C colon backslash IMan backslash OutputData backslash Docs, File Name orders.xml, Encoding Method Unicode UTF-8, with Overwrite Existing File ticked.

Field Value
Target File Or http(s) Url — see the Webservices cookbook
File System Windows
File Path C:\IMan\OutputData\Docs
File Name orders.xml
Encoding Method Unicode (UTF-8)
Overwrite Existing File ✔ Otherwise each run writes a new, uniquely named file

The document it produces, trimmed to one order:

<?xml version="1.0" encoding="utf-8"?>
<Orders>
  <Order id="FBRN-309242">
    <Reference type="Web" currency="USD" />
    <Party Type="Contact">
      <Title>Mr</Title>
      <FirstName>Ronald</FirstName>
      <LastName>English</LastName>
      <Email>[email protected]</Email>
    </Party>
    <Party Type="SoldTo">
      <Name>Imperial Soap Inc</Name>
      <City>Fairbanks</City>
      <Country>USA</Country>
      <PostalCode>79160</PostalCode>
    </Party>
    <OrderDate>2016-03-11</OrderDate>
    <SalesTotal>282.00</SalesTotal>
    <Lines>
      <Line no="1">
        <Qty>5</Qty>
        <SkuCode>A1-103/0</SkuCode>
        <Description>Big Desklamp</Description>
        <UnitPrice>20.00</UnitPrice>
      </Line>
      <Line no="2">
        <Qty>30</Qty>
        <SkuCode>A1-401/0</SkuCode>
        <Description>Big Style Notepad</Description>
        <UnitPrice>5.10</UnitPrice>
      </Line>
    </Lines>
    <Charges>
      <Charge type="Delivery">
        <Amount>29.00</Amount>
      </Charge>
    </Charges>
  </Order>
</Orders>

Which XPath names the repeating node

This is the first thing to get right and the writer gives no hint about it. A child transaction's Transaction Type XPath names the container, and the repeating node is the first step of every field's XPath.

That is the opposite of the Xml Reader, where the entry point names the repeating element itself.

The root transaction

The Xml Writer Field Mapping tab with the Order transaction selected. Initial XPath is Orders, Transaction Type XPath is Order, the Output panel lists Order, OrderLine and Charge, and the field grid shows Field Name, Type, Export, XPath, Relative and Attribute columns.

Control Value
Initial XPath Orders The outermost element; everything is built beneath it
Current Transaction Id Order Which transaction the grid below is showing
Transaction Type XPath Order Relative to the Initial XPath

The root behaves the way you would expect: Order is created once per record, so three orders produce three <Order> elements inside one <Orders>.

The child transactions

The Xml Writer Field Mapping tab with OrderLine selected. Transaction Type XPath is Lines, and the field grid maps LineNo to XPath Line with Attribute no, Quantity to Line slash Qty, ItemCode to Line slash SkuCode, Description to Line slash Description and Price to Line slash UnitPrice.

OrderLine's Transaction Type XPath is Lines, not Lines/Line — and every field beneath it starts Line/:

Field XPath Attribute
LineNo Line no
Quantity Line/Qty
ItemCode Line/SkuCode
Description Line/Description
Price Line/UnitPrice

Charge is built the same way — Charges on the transaction, Charge/ on the fields:

The Xml Writer Field Mapping tab with Charge selected. Transaction Type XPath is Charges, ChargeType maps to XPath Charge with Attribute type, and Amount to Charge slash Amount.

Lines/Line on the transaction merges every line into one node

Give the transaction the full path and the writer creates Lines/Line once, then writes every record's fields into that same <Line>. Two order lines come out as:

<Lines>
  <Line no="2">
    <Qty>5</Qty><SkuCode>A1-103/0</SkuCode>
    <Qty>30</Qty><SkuCode>A1-401/0</SkuCode>
  </Line>
</Lines>

One node, both lines' values in it, and the no attribute holding whichever record was written last. Nothing errors and the preview grid is correct, so the only way to notice is to read the file.

The mechanism explains it: the writer creates the transaction's skeleton once per parent record and positions itself inside it. Whatever repeats has to come from the field paths, which are rebuilt for every record.

The root is the exception

The root transaction re-creates its own node per record, so Order — a single step naming the repeating element — is right there and wrong on a child. It is asymmetric, and it is the reason a mapping that looks consistent across all three transactions is wrong on two of them.

Writing attributes

A value is written as an attribute rather than as element content by naming the attribute in the field's Attribute box. The XPath still says which node it goes on.

The Xml Writer's Field Mapping dialog for OrderType, annotated. Field Name is OrderType, Export Field and Is Relative XPath are ticked, XPath is Reference with a callout reading SAME ON BOTH FIELDS, and Attribute is type with a callout reading DIFFERENT ON EACH.

Two fields carrying the same XPath and different Attributes produce one node with two attributes. OrderType and Currency both have the XPath Reference; their Attribute boxes hold type and currency:

Field XPath Attribute
OrderType Reference type
Currency Reference currency
<Reference type="Web" currency="USD" />

The node is created once and each field adds its own attribute to it. In a real document the XPath is usually several steps — Header/Reference — and the same rule applies at whatever depth it names.

An empty XPath puts the attribute on the transaction's own node

OrderId has no XPath at all and an Attribute of id, and together they produce <Order id="FBRN-309242">. The same is true of LineNo (XPath Line, Attribute no) — there the XPath names the repeating node, so the attribute lands on it rather than on a child.

An empty XPath and an empty Attribute is not valid: the field has nowhere to go, and the transform reports it rather than writing nothing.

Attribute paths

An XPath step may carry an attribute subexpression:

Node[@AttributeName='AttributeValue']/NodeName

This writes separate nodes of the same name, distinguished by an attribute, out of a single record — without the several transforms it would otherwise take to hierarchise the data first.

The Xml Writer's Field Mapping dialog for Company, annotated. XPath holds Party at-Type equals SoldTo in square brackets slash Name, with a callout reading PREDICATE PICKS THE NODE.

The order's own address and its contact are both on one record, and both come out as Party nodes:

Field XPath
Company Party[@Type='SoldTo']/Name
City Party[@Type='SoldTo']/City
Country Party[@Type='SoldTo']/Country
Postcode Party[@Type='SoldTo']/PostalCode
Title Party[@Type='Contact']/Title
CustomerFirstName Party[@Type='Contact']/FirstName
CustomerLastName Party[@Type='Contact']/LastName
Email Party[@Type='Contact']/Email
<Party Type="Contact">
  <Title>Mr</Title>
  <FirstName>Ronald</FirstName>
  <LastName>English</LastName>
  <Email>[email protected]</Email>
</Party>
<Party Type="SoldTo">
  <Name>Imperial Soap Inc</Name>
  <City>Fairbanks</City>
  <Country>USA</Country>
  <PostalCode>79160</PostalCode>
</Party>

Eight fields, two nodes. Fields sharing a predicate are gathered into the node that predicate describes; a different predicate value makes a different node. The classic case is a billing and a delivery address on one order row — Address[@Type='BillTo']/Address1 and Address[@Type='ShipTo']/Address1.

The attribute named in the predicate is written for you. Nothing maps to Type, and both nodes carry it.

The node order is the field order, not the predicate order

Contact comes out before SoldTo because Title is above Company in the field grid. If the receiving system cares about element order, reorder the rows.

Using a template document

Scenario

The receiving system expects a fixed envelope. A SOAP Envelope and Body; a header block carrying a version and a sender id; constant values inside each record that no field in the dataset supplies.

That can be built from the field grid, but it is built badly: it needs a Map transform carrying one static field per constant node, and the constants then live in the integration rather than in the document they belong to. The shape of the document is nowhere visible in one piece.

Solution

Give the Writer a Template Document — an XML file that becomes the output document, with the Writer's XPath expressions filling in the parts that vary.

The Xml Writer Setup tab, Options section, with Template Document set to C colon backslash IMan backslash InputData backslash Docs backslash xml backslash order-template.xml.

The control is on the Writer's Setup tab, in the Options section; entering a path is the only thing that turns the feature on.

The template is reloaded for every document the transform writes, so with Generate File Per Transaction in use each file starts from the template again.

Worked example

sample-data/xml/order-template.xml, a document that must go out inside a fixed envelope:

<?xml version="1.0" encoding="utf-8"?>
<Transmission>
  <Header>
    <Version>2.1</Version>
    <Sender>REALISABLE</Sender>
  </Header>
  <Orders>
    <Order>
      <DocumentType>ORDERS</DocumentType>
      <!-- kept: no field maps to this comment or to DocumentType -->
      <SalesTotal>0.00</SalesTotal>
    </Order>
  </Orders>
</Transmission>

The Xml Writer Field Mapping tab for the template writer. Initial XPath is Transmission slash Orders, Transaction Type XPath is Order, and four fields are exported: OrderId as attribute id, Company to Customer, OrderDate to OrderDate and SalesTotal to SalesTotal.

  • Initial XPath — Transmission/Orders. With a template this node is not created: the Writer navigates to the one already in the template.
  • Transaction Type XPath for the order transaction — Order, so each record produces one Order beneath Orders.

The single <Order> in the template is the pattern for every order written. Four fields are mapped: OrderId as the id attribute, SalesTotal onto the template's own SalesTotal, and Company and OrderDate onto nodes the template does not have.

What survives, what is overwritten, and what is added

This is the part that makes templates worth using, and it is not obvious. The output for one order, from the template above:

<Transmission>
  <Header><Version>2.1</Version><Sender>REALISABLE</Sender></Header>
  <Orders>
    <Order id="FBRN-309242">
      <DocumentType>ORDERS</DocumentType>
      <!-- kept: no field maps to this comment or to DocumentType -->
      <SalesTotal>282.00</SalesTotal>
      <Customer>Imperial Soap Inc</Customer>
      <OrderDate>2016-03-11</OrderDate>
    </Order>
    …
  </Orders>
</Transmission>
  • Everything outside the Initial XPath is kept verbatim — the Header block above, and in a SOAP document the whole envelope. Attributes and text on the Initial XPath node itself are kept too, as are comments outside the root.
  • Everything inside the Initial XPath is cleared. Its child elements are deleted before writing, so the template's example <Order> does not appear in the output in addition to the real ones.
  • Inside the record pattern, anything no field maps to is kept — including literal values, attributes and XML comments. DocumentType and the comment beside it are written on every order without any field carrying them.
  • A mapped field whose XPath matches a node in the pattern replaces its value. SalesTotal comes out as 282.00, not the template's 0.00.
  • A mapped field with no matching node is appended after the template's nodes within that record, in field-grid order.

A transaction whose Transaction Type XPath is not found in the template is built from scratch as normal, so only part of a document need be templated.

Picking one of several patterns

Where the template holds more than one candidate node, the Transaction Type XPath may carry a predicate to choose between them — Order[@type='Sales']. Without one the first match is used.

Three things to get right

The Initial XPath must exist in the template

There is no validation of this, at design time or at load. If the Initial XPath names a node the template does not contain, nothing is created and nothing reports it — the transform fails on the first record instead.

For the same reason do not set the Initial XPath to / while a template is in use. That selects every element in the document, and the template is deleted rather than filled in.

The template's namespace prefixes are the ones your XPaths must use

Namespaces declared on the template's root element are registered automatically, so XPath expressions can use those prefixes without the namespace being listed again under Xml Options.

Listing it again is not an error, but it is not an override either: a declaration whose URI the template already declares is discarded, prefix and all. Where the two disagree the template wins. Match the template's prefixes rather than trying to rename them.

The path is a plain file path on the IMan server

It is read directly from the file system of the machine running the integration — not through a File System connection, so no FTP, SFTP or cloud location — and it is read once, as the transform starts. It cannot contain field references and cannot vary per transaction.

Because the path is stored in the integration, it also has to be valid on every machine that integration is deployed to. A missing file fails the transform with "File [...] could not be opened.", which does not mention the word template.

When it does not work

  • Every child record's values in one node. The child transaction's XPath names the repeating element rather than its container. See above.
  • A second, empty wrapper appears. A field path repeating the container — Lines/Line/Qty beneath a transaction already on Lines — builds a Lines inside Lines.
  • An attribute is written on the wrong node. The Attribute goes on whatever node the XPath ends at, so Header/Reference with an Attribute writes it on Reference, not on Header.
  • No file, and no error. Overwrite Existing File unticked with a file already there.

Verified against IMan 6.1 on 3 September 2026, against the DOCSWRITE integration described in sample-data/README.md.