---
title: Serialize XDesign XML tree
summary: Converts an in-memory report XML tree into the xPression-compatible markup format, propagating primary keys into descendant foreign-key collections.
status: draft
owner: SAIF Doc Gen
last_reviewed: 2026-07-30
library: SAIF.Services.Printing
reference_type: package
operation_id: OP-PRT-09
trigger: Caller invokes XDesignXDocument.ToXpression or XDesignXElement.ToXpression before submitting a report for preview or distribution
---

# Serialize XDesign XML tree

Before report XML can be sent to xPression, it must be rendered from the .NET `XDocument`/`XElement`-derived tree (`XDesignXDocument`/`XDesignXElement`) into xPression's specific markup, with primary keys propagated down as foreign keys on descendant elements. This operation is the serialization step invoked internally by [Render report](render-report.md) (through `ToXpression()`) and is also available for callers building xPression payloads directly.

| Field | Value |
| --- | --- |
| **Operation ID** | OP-PRT-09 |
| **Trigger** | Caller invokes `XDesignXDocument.ToXpression()` (delegates to the root element) or `XDesignXElement.ToXpression()` directly |
| **Inputs** | An `XDesignXDocument` with an `XDesignXElement` root, or an `XDesignXElement` tree with `AddKey`-registered primary keys |
| **Outputs** | Serialized xPression-compatible XML text |
| **Primary components** | `Reporting.XDesignXDocument.ToXpression`, `Reporting.XDesignXElement.ToXpression`, `Reporting.XDesignXElement.PropagateKeys` |
| **Entry point** | `Services\SAIF.Services.Printing\Reporting\XDesignXDocument.vb`, `Services\SAIF.Services.Printing\Reporting\XDesignXElement.vb` |

## Steps

1. `XDesignXDocument.ToXpression` checks that the document's `Root` is not `Nothing` and is an `XDesignXElement`.
   - If both conditions hold: it delegates to the root element's `ToXpression()`.
   - If not: it returns an empty string.
2. `XDesignXElement.ToXpression(tabIndex)` is called with `tabIndex = 0` for the root call.
   - On the root call only (`tabIndex = 0`): the method first calls `PropagateKeys()`, which recursively walks every descendant `XDesignXElement`, clears its existing foreign-key list, adds each of the current element's `Keys` (primary keys registered via `AddKey`) as a foreign key on elements that have child elements, adds each inherited foreign key from the parent, and recurses into further descendants.
3. If the current element has no child elements, `ToXpression` renders it as a single leaf element: its name and (HTML/XML-escaped) value via `RenderElement`.
4. If the current element has child elements, `ToXpression`:
   - Emits the opening tag via `RenderStartElement`.
   - Emits each propagated foreign-key element (from step 2) via `RenderElement`, before any child content.
   - Recurses into each child element, calling `ToXpression(tabIndex + 1)` on `XDesignXElement` children, or converting non-`XDesignXElement` children via the `ToSAIFXElement` extension method first.
   - Emits the closing tag via `RenderEndElement`, followed by a line break when `tabIndex > 0`.
5. Element values are escaped using `System.Security.SecurityElement.Escape` before being written, so XML-significant characters in report data do not break the generated markup.
6. The fully serialized string is returned up the recursion to the original `ToXpression` caller.

## Process flow

The following diagram visualizes the key-propagation and recursive rendering sequence.

```mermaid
flowchart TD
	Start([ToXpression called on document]) --> RootCheck{Root is<br>XDesignXElement?}
	RootCheck -->|No| Empty([Return empty string])
	RootCheck -->|Yes| Propagate[PropagateKeys: push primary keys<br>down as foreign keys on descendants]
	Propagate --> Leaf{Element has<br>child elements?}
	Leaf -->|No| RenderLeaf[Render as single<br>escaped leaf element]
	Leaf -->|Yes| OpenTag[Render opening tag]
	OpenTag --> FKeys[Render propagated<br>foreign-key elements]
	FKeys --> Recurse[Recurse into each<br>child element]
	Recurse --> CloseTag[Render closing tag]
	RenderLeaf --> End([Return serialized XML text])
	CloseTag --> End
```

## Failure and edge-case behavior

- Calling `ToXpression()` on a document whose root is not an `XDesignXElement` (for example, a plain `XElement`) returns an empty string rather than throwing or falling back to a generic serialization.
- `PropagateKeys` only runs once, on the root call (`tabIndex = 0`); calling `XDesignXElement.ToXpression` directly on a non-root element with a non-zero `tabIndex` skips key propagation for that subtree.*
- Foreign-key propagation only adds keys to descendant elements that already have their own child elements (`x.HasElements`); leaf descendants do not receive propagated foreign keys.

## Related documentation
- [Operations and processes](../operations-processes.md)
- [Business rules](../business-rules.md)

> **Note:** Statements marked with * were inferred from code structure, naming conventions, or
> contextual evidence where direct confirmation was not available in source artifacts. Statements
> marked with ** could not be confirmed; treat as unknown until verified.

## Sources
- `Services\SAIF.Services.Printing\Reporting\XDesignXDocument.vb`
- `Services\SAIF.Services.Printing\Reporting\XDesignXElement.vb`
