An XFA field looks blank before and after saving, yet a downstream system reports that its value changed. A space or line break may be present where an empty string was expected. HotPDF preserves whitespace-only scalar text in the applicable Form and Template value elements during a round trip
Why can different values all look blank?
An absent value, an empty string and a string containing one space can all look blank on a form. Their meanings can differ. A receiving system might interpret an empty value as “clear this field” and an absent value as “no update supplied”; a line break can delimit items in a multiline or multi-select value. XML also contains indentation whitespace between elements, so the position of the characters matters. A space inside a scalar text value belongs to that value, whereas whitespace placed between unrelated elements can simply format the document. A visual check of the field cannot tell the application which character sequence was submitted
<value xmlns="http://www.xfa.org/schema/xfa-form/2.8/">
<text> </text>
</value>
In this simplified fragment, the space between the text tags is the scalar value. Whitespace surrounding the element serves as indentation. The fragment isolates that distinction; a complete XFA document includes the enclosing form and namespace context
Why does the XML namespace matter?
A local name alone is insufficient to identify an XFA value. Another XML vocabulary can contain elements called value and text, while the namespace URI and element relationship determine what they mean in the document. HotPDF checks the XFA Form or Template namespace and the relationship between those elements when retaining scalar text. A prefix is only an alias for a namespace URI: two packets can use different prefixes and still refer to the same vocabulary. Line breaks have an additional role in multi-select data, where they can delimit selected items; empty items may leave a value made entirely of separators. Trim that value and the item boundaries disappear. We would preserve the submitted character sequence at the file boundary and apply business normalization later, where the meaning of an empty item is known
A user may deliberately enter a space-only value. The application can allow it or reject it according to the field's business rules, but an XML parser cannot infer whether the space represents an address, a separator or an intentional entry. That decision belongs where the application knows what the field means
Round-trip the form with Delphi
The first Delphi routine opens an existing PDF and saves a copy without making field edits. Use it to establish the round-trip behavior before you add the application's business rules and other transformations, paying particular attention to scalar values containing only a space or a line feed
uses
SysUtils, HPDFDoc, HPDFXFARuntime;
procedure SaveFormCopy(const InputFile, OutputFile: string);
var
Pdf: THotPDF;
begin
Pdf := THotPDF.Create(nil);
try
if Pdf.LoadFromFile(InputFile) <= 0 then
raise Exception.Create('Cannot open the PDF');
Pdf.SaveLoadedDocument(OutputFile);
finally
Pdf.Free;
end;
end;
Once the no-edit round trip is understood, apply the field edits used by the application and read the saved values again. Keeping the input and output available makes it possible to distinguish the document round trip from a change introduced by application data handling
Inspect characters, not just what the field displays
A blank-looking field needs a diagnostic that shows its characters. Log its length and an escaped representation, so a newline appears as a marker rather than merely moving the next line of the log. The routine below creates an XFA runtime for a loaded PDF and prints each widget value as UTF-16 code units. A space appears as 32 and a line feed as 10. In our save-and-reopen check, a line feed placed in an XFA text value was read back as UTF-16 unit 10 after the PDF was reopened
procedure DumpXfaWidgetValues(Pdf: THotPDF);
var
Runtime: TXFAWidgetRuntime;
State: TXFAWidgetState;
I, J: Integer;
begin
Runtime := Pdf.CreateLoadedXFAWidgetRuntime;
if Runtime = nil then
raise Exception.Create('The PDF has no XFA runtime');
try
for I := 0 to Runtime.WidgetCount - 1 do
begin
State := Runtime.Widgets[I];
Writeln('Widget ', I, ', length ', Length(State.Value));
for J := 1 to Length(State.Value) do
Writeln(' UTF-16 unit: ', Ord(State.Value[J]));
end;
finally
Runtime.Free;
end;
end;
Create a fresh runtime for the reopened PDF before reading its values. Exercise an absent value, an empty element, one space, one line feed and ordinary text; if the application uses multi-select fields, include empty items there too. Their displays can look alike even when their character sequences differ. Namespace and enclosing element still matter, because another vocabulary can use the same local names. Numeric output makes the invisible characters concrete: a tab is code unit 9, a line feed 10, a carriage return 13 and a space 32. An empty string has length zero; a single line feed has length one. For templates using different XFA namespace versions, use the versions actually received by the application and keep the field path with the output
A logger that prints only the field's visible text can hide a line feed by moving the next log entry to another line. Printing each code unit avoids that ambiguity. Keep the field name and the value length beside the numbers you log: 10 in a one-unit value describes a different input from an empty string followed by a log separator. Use the same diagnostic when you read the original field and the reopened field so the character sequence is visible on both sides of the round trip
Do not trim as a convenience
Calling Trim can be reasonable when a field's business rules explicitly ignore surrounding whitespace. It is a risky default for every value in a form, particularly when line breaks delimit multi-select items. Keep the original value as you pass through the document boundary until your application knows what the field means. One application model can keep both the raw value for an exact round-trip check and a normalized value for display or downstream processing. That makes the normalization decision visible instead of silently turning it into part of every PDF save. The receiving system's rules determine what happens next. A space-only value may be meaningful for one field and invalid for another; a line break may be content in one field and an item separator in another. Keeping the raw value does not prevent the application from applying those rules. It gives the validation step the submitted characters to work with, and lets the application retain the original sequence when the business workflow calls for a lossless round trip
Check a rejected operation too
If the application groups several form edits into one operation, include a case in which a later edit is rejected. After you apply the edit, read the resulting form state and check that an earlier accepted value, including its whitespace, matches the workflow's expectation. For a report of a blank-looking change, the field path, escaped value, length and namespace are more informative than the visible field alone. Those details identify the value being discussed and the character sequence the receiving code should expect. The same field path should be checked after reopening the saved document, with the value length recorded beside its code units
An automated round-trip check should compare the characters at the field boundary before and after saving. Pretty-printed XML can change indentation or attribute order without changing a scalar value; it can also make two different whitespace values look deceptively similar in a log. When the value differs, the enclosing XML and namespace provide the context needed to explain why. The dynamic XFA runtime overview covers form interaction, while XFA rich text and hyperlinks discusses another kind of text content. The document APIs belong to the HotPDF Delphi Component