---
title: Generate timer results XML
summary: Convert the in-memory timer dictionary into an XML document that summarizes elapsed timing data.
status: draft
owner: SAIF
last_reviewed: 2026-07-30
library: SAIF.Framework.CodeTimer
reference_type: package
operation_id: CT-OP-004
trigger: Caller invokes CodeTimer.Results() or CodeTimer.Results(bool includeTimeSpans).
---

# Generate timer results XML

This operation transforms the flat, semicolon-delimited timer dictionary into a hierarchical result tree and serializes that tree as XML. It is the library's primary reporting path: it is how a caller who has been starting and stopping timers throughout a run turns the accumulated data into a document that can be inspected, logged, or archived.

| Field | Value |
| --- | --- |
| **Operation ID** | CT-OP-004 |
| **Trigger** | Caller invokes `CodeTimer.Results()` or `CodeTimer.Results(bool includeTimeSpans)` |
| **Inputs** | Optional `includeTimeSpans` flag |
| **Outputs** | `XDocument` rooted at `<Timer>`, or `null` when no timer data exists |
| **Primary components** | `CodeTimer.Results`, `CodeTimerResult.CodeTimerResult`, `CodeTimerResult.CreateItems`, `CodeTimerResult.OutputXml`, `CodeTimerResult.RecurseXml` |
| **Entry point** | `SAIF.Framework.CodeTimer\SAIF.Framework.CodeTimer\CodeTimer.cs` |

## Steps

1. Normalize the call to `CodeTimer.Results(bool includeTimeSpans)` — the parameterless overload simply delegates to `Results(false)`, so time-span detail is opt-in rather than the default.
2. Check whether the static `data` dictionary contains any entries at all.
   - If the dictionary is empty, return `null` immediately rather than constructing and returning an empty `<Timer>` document.
3. Construct a new `CodeTimerResult(data)`, whose constructor immediately calls `CreateItems()` to build the reporting tree before any XML is produced.
4. Within `CreateItems()`, iterate every `CodeTimerEntry` currently in the dictionary.
   - If any entry is still marked as running, abandon the reporting attempt and throw under [BR-003](../business-rules.md#br-003-results-cannot-be-requested-while-any-timer-is-still-active) — a report is only meaningful once every timer it would summarize has actually finished.
   - Split each entry's `;`-delimited timer name into its component parts, and walk or create the corresponding `CodeTimerItem` nodes so the flat key space becomes a proper parent/child tree.
   - Populate the leaf node that matches the entry's full key with its elapsed time, quantity, start/stop timestamps, shortest/longest span, and span history; populate any intermediate node created purely for grouping with sentinel values such as `Elapsed = -1` so it can be distinguished from a real, measured timer.
5. Call `OutputXml(includeTimeSpans)`, which creates a new `XDocument` with a single `<Timer>` root element to hold the serialized tree.
6. Recursively serialize each top-level `CodeTimerItem` through `RecurseXml(...)`, which decides per node which attributes are worth emitting.
   - Emit the `short`, `long`, `avg`, and `qty` attributes only when the item has been measured more than once (`Qty > 1`); a single-execution timer has no meaningful range or average to report ([BR-006](../business-rules.md#br-006-result-xml-omits-statistically-insignificant-attributes)).
   - Emit the `ms` attribute only when the item's elapsed value is greater than zero, so grouping-only nodes stay free of a misleading duration ([BR-006](../business-rules.md#br-006-result-xml-omits-statistically-insignificant-attributes)).
   - Emit `<span>` child elements only when the caller requested `includeTimeSpans`, the item recorded more than one span, and each individual span's computed duration is greater than zero milliseconds — a single span or a zero-length span carries no additional signal ([BR-006](../business-rules.md#br-006-result-xml-omits-statistically-insignificant-attributes)).
7. Recurse into an item's children only when that item both has children and has a positive `Elapsed` value; once every reachable node has been visited, return the completed `XDocument` to the caller.

## Process flow

The following diagram visualizes this operation's control flow.

```mermaid
flowchart TD
	Start([Results request]) --> HasData{Any timer data?}
	HasData -->|No| NoData([Return null])
	HasData -->|Yes| BuildResult[Construct CodeTimerResult]
	BuildResult --> Running{Any entry still running?}
	Running -->|Yes| Error([Throw running-timer exception])
	Running -->|No| BuildTree[Create CodeTimerItem tree]
	BuildTree --> Serialize[Serialize XML output]
	Serialize --> EndOk([Return XDocument])
```

## Failure and edge-case behavior

- Requesting results while any timer in the store is still running throws under [BR-003](../business-rules.md#br-003-results-cannot-be-requested-while-any-timer-is-still-active) — the caller must ensure every started timer has been stopped first.
- `Results()` returns `null`, not an empty document, when no timer entries have ever been captured; callers must check for `null` rather than assuming an `XDocument` is always returned.
- Even with `includeTimeSpans` set to `true`, a timer that was only ever started and stopped once produces no `<span>` elements, because `RecurseXml` requires more than one recorded span before it will serialize any ([BR-006](../business-rules.md#br-006-result-xml-omits-statistically-insignificant-attributes)).
- Intermediate parent nodes that exist only to group child timers under a shared key prefix do not recurse into their children unless that parent node itself also has a positive `Elapsed` value, which can leave otherwise-valid child measurements unreported if the grouping node was never itself timed.

## Related documentation
- [Operations and processes](../operations-processes.md)
- [Business rules](../business-rules.md)
- [Configuration](../configuration.md)
- [API reference](../api/index.md)

## Sources
- SAIF.Framework.CodeTimer\SAIF.Framework.CodeTimer\CodeTimer.cs
- SAIF.Framework.CodeTimer\SAIF.Framework.CodeTimer\CodeTimerEntry.cs
- SAIF.Framework.CodeTimer\SAIF.Framework.CodeTimer\CodeTimerItem.cs
- SAIF.Framework.CodeTimer\SAIF.Framework.CodeTimer\CodeTimerResult.cs
