InstantXML
File-based XML persistence broker for InstantObjects.
Overview
The InstantXML unit provides a file-based persistence broker that stores business objects as XML files in the file system. Each object is saved as a separate XML file with a structured naming convention, organized into folders by class/storage name.
This broker is ideal for:
- Small to medium datasets
- Prototyping and development
- Portable applications without database dependencies
- Data exchange and archival scenarios
- Offline/disconnected applications
File Structure:
RootFolder/
├─ Company/
│ ├─ TCompany.ABC123.1.xml
│ ├─ TCompany.DEF456.1.xml
│ └─ TCompany.GHI789.2.xml
├─ Contact/
│ ├─ TContact.001.1.xml
│ └─ TContact.002.1.xml
└─ Product/
└─ TProduct.PROD001.1.xmlFile Naming Convention: ClassName.ObjectId.UpdateCount.xml
Key Classes
TXMLFilesAccessor
Low-level connection component that manages XML file operations.
Inheritance:
TComponent → TCustomConnection → TXMLFilesAccessorKey Features:
- Creates and manages folder structure
- Reads/writes objects to XML files
- Supports custom file naming via override
- UTF-8 or ISO-8859-1 encoding options
- Custom load/save events for redirection
Properties
| Property | Type | Default | Description |
|---|---|---|---|
| RootFolder | string | '' | Root directory for XML file storage |
| XMLFileFormat | TXMLFileFormat | xffUtf8 | File encoding (xffUtf8 or xffIso) |
| OnCustomLoadXMLFile | TXMLFileOpenEvent | nil | Custom file loading handler |
| OnCustomSaveToXMLFile | TXMLFileSaveEvent | nil | Custom file saving handler |
Methods
GetObjectFileName
function GetObjectFileName(const AStorageName, AObjectClassName,
AObjectId: string): string; virtual;Returns the full file path for an object. Default implementation:
Result := RootFolder + AStorageName + PathDelim + AObjectClassName + '.'
+ AObjectId + '.1' + DOT_XML_EXT;
// Example: C:\Data\Company\TCompany.ABC123.1.xmlOverride this method to customize file naming or storage location.
ReadInstantObject
function ReadInstantObject(const AObject: TInstantObject;
const AStorageName, AObjectId: string;
out AObjectUpdateCount: Integer): Boolean;Loads object from XML file. Returns True if successful.
WriteInstantObject
function WriteInstantObject(const AObject: TInstantObject;
const AStorageName: string;
out AObjectUpdateCount: Integer): Boolean;Saves object to XML file. Returns True if successful.
DeleteInstantObject
function DeleteInstantObject(const AObject: TInstantObject;
const AStorageName: string): Boolean;Deletes object's XML file. Returns True if successful.
LocateInstantObject
function LocateInstantObject(const AStorageName, AObjectClassName,
AObjectId: string): Boolean;Checks if object file exists. Returns True if found.
LoadFileList
procedure LoadFileList(const AFileList: TStringList;
const AStorageNames: TStrings;
const AFilterWildCard: string = '');Loads list of XML files from specified storage folders.
Parameters:
AFileList: Receives list of filenamesAStorageNames: List of folders to searchAFilterWildCard: Optional wildcard filter (e.g., 'TCompany*.xml')
TInstantXMLConnectionDef
Connection definition for XML broker.
Properties
| Property | Type | Description |
|---|---|---|
| RootFolder | string | Root folder for XML files |
| XMLFileFormat | TXMLFileFormat | UTF-8 or ISO encoding |
TInstantXMLConnector
Main connector component for XML file persistence.
Inheritance:
TComponent → TInstantConnector → TInstantConnectionBasedConnector → TInstantXMLConnectorProperties
| Property | Type | Default | Description |
|---|---|---|---|
| Connection | TXMLFilesAccessor | nil | XML files accessor component |
| UseTransactions | Boolean | False | Transactions not supported (always False) |
| LoginPrompt | Boolean | False | No login required |
| UseUnicode | Boolean | False | Unicode support (deprecated) |
| BlobStreamFormat | TInstantStreamFormat | sfXML | Always XML format |
| ReadObjectListWithNoLock | Boolean | True | No locking mechanism |
Methods
InternalBuildDatabase
procedure InternalBuildDatabase(Scheme: TInstantScheme); override;Creates root folder if it doesn't exist. Does not create class-specific folders (created on demand when objects are written).
TInstantXMLBroker
Broker that manages resolvers for XML persistence.
Inheritance:
TInstantBroker → TInstantCustomRelationalBroker → TInstantXMLBrokerProperties
| Property | Type | Description |
|---|---|---|
| Connector | TInstantXMLConnector | Parent connector |
| ResolverCount | Integer | Number of registered resolvers |
| Resolvers[Index] | TInstantXMLResolver | Resolver by index |
Methods
FindResolver
function FindResolver(const StorageName: string): TInstantXMLResolver;Finds existing resolver for a storage name (folder).
CreateResolver
function CreateResolver(const StorageName: string): TInstantXMLResolver;Creates a new resolver for a storage name.
EnsureResolver
function EnsureResolver(Map: TInstantAttributeMap): TInstantCustomResolver; override;Returns existing resolver or creates a new one for the attribute map's storage.
TInstantXMLResolver
Handles object persistence operations for a specific storage (folder).
Inheritance:
TInstantCustomResolver → TInstantXMLResolverProperties
| Property | Type | Description |
|---|---|---|
| Broker | TInstantXMLBroker | Parent broker |
| StorageName | string | Storage folder name |
Methods
InternalStoreMap
procedure InternalStoreMap(AObject: TInstantObject;
Map: TInstantAttributeMap;
ConflictAction: TInstantConflictAction;
Info: PInstantOperationInfo); override;Saves object to XML file. Handles ID changes by deleting old file.
InternalRetrieveMap
procedure InternalRetrieveMap(AObject: TInstantObject;
const AObjectId: string; Map: TInstantAttributeMap;
ConflictAction: TInstantConflictAction;
Info: PInstantOperationInfo;
const AObjectData: TInstantAbstractObjectData); override;Loads object from XML file.
InternalDisposeMap
procedure InternalDisposeMap(AObject: TInstantObject;
Map: TInstantAttributeMap;
ConflictAction: TInstantConflictAction;
Info: PInstantOperationInfo); override;Deletes object's XML file.
TInstantXMLQuery
Query implementation that loads and filters XML files in memory.
Inheritance:
TInstantQuery → TInstantCustomRelationalQuery → TInstantXMLQueryHow it works:
- Loads all XML files from specified storage folders
- Filters by class name
- Creates object references for matching files
- Applies IQL WHERE filter (in memory)
- Sorts by ORDER BY clause (QuickSort)
- Returns result set
Properties
| Property | Type | Description |
|---|---|---|
| StorageNames | TStringList | Folders to search (populated by translator) |
| ObjectClassNames | TStringList | Classes to include (populated by translator) |
| FilterWildCard | string | Filename wildcard filter |
| ObjectReferenceCount | Integer | Number of matching objects |
| ObjectReferences[Index] | TInstantObjectReference | Object reference by index |
Methods
InternalOpen
procedure InternalOpen; override;Opens query:
- Parses IQL command
- Loads file list from storage folders
- Creates object references
- Sorts if ORDER BY present
SortObjectReferences
procedure SortObjectReferences;Sorts object references using QuickSort based on ORDER BY clause.
TInstantXMLTranslator
IQL to XML query translator.
Inheritance:
TInstantRelationalTranslator → TInstantXMLTranslatorMethods
TranslateClassRef
function TranslateClassRef(ClassRef: TInstantIQLClassRef;
Writer: TInstantIQLWriter): Boolean; override;Translates IQL class reference to storage/class name lists. Handles inheritance (ANY keyword).
Constants
const
XML_UTF8_HEADER = '<?xml version="1.0" encoding="UTF-8"?>';
XML_ISO_HEADER = '<?xml version="1.0" encoding="ISO-8859-1"?>';
XML_EXT = 'xml';
DOT_XML_EXT = '.xml';
XML_WILDCARD = '*.xml';Types
TXMLFileFormat
type
TXMLFileFormat = (xffUtf8, xffIso);File encoding format:
- xffUtf8: UTF-8 encoding (default, recommended)
- xffIso: ISO-8859-1 encoding (for legacy compatibility)
Event Types
type
TXMLFileOpenEvent = function(const AObject: TInstantObject;
const AObjectId, AFileName: string): Boolean of Object;
TXMLFileSaveEvent = function(const AObject: TInstantObject;
const AFileName: string): Boolean of Object;Usage Patterns
Basic Setup
Configure XML connector:
uses
InstantXML;
var
XMLConnection: TXMLFilesAccessor;
XMLConnector: TInstantXMLConnector;
begin
// Create connection
XMLConnection := TXMLFilesAccessor.Create(Self);
XMLConnection.RootFolder := 'C:\MyApp\Data';
XMLConnection.XMLFileFormat := xffUtf8;
// Create connector
XMLConnector := TInstantXMLConnector.Create(Self);
XMLConnector.Connection := XMLConnection;
XMLConnector.Connected := True;
end;Design-Time Setup
- Drop
TXMLFilesAccessoron form - Set
RootFolderproperty - Drop
TInstantXMLConnectoron form - Set
Connectionproperty toTXMLFilesAccessor - Set
Connected := True
Programmatic Connection
procedure ConnectToXMLDatabase(const DataFolder: string);
var
Connector: TInstantXMLConnector;
begin
Connector := TInstantXMLConnector.Create(nil);
try
Connector.IsDefault := True;
Connector.BrokerClass := TInstantXMLBroker;
// Connection string format: RootFolder
Connector.ConnectionDef := TInstantXMLConnectionDef.Create(
'XML;' + DataFolder, True);
Connector.Connected := True;
ShowMessage('Connected to XML database at: ' + DataFolder);
except
Connector.Free;
raise;
end;
end;Storing and Retrieving Objects
Objects are automatically stored as XML files:
var
Company: TCompany;
begin
// Create and store
Company := TCompany.Create(XMLConnector);
try
Company.Id := 'ABC123';
Company.Name := 'Acme Corporation';
Company.Store;
// Creates: C:\MyApp\Data\Company\TCompany.ABC123.1.xml
finally
Company.Free;
end;
// Retrieve
Company := TCompany.Retrieve('ABC123', False, False, XMLConnector);
try
ShowMessage(Company.Name); // 'Acme Corporation'
finally
Company.Free;
end;
end;Querying XML Files
Use IQL to query objects:
var
Query: TInstantQuery;
begin
Query := TInstantQuery.Create(nil);
try
Query.Connector := XMLConnector;
Query.Command := 'SELECT * FROM TCompany WHERE Name LIKE ''%Corp%''';
Query.Open;
while not Query.EOF do
begin
ShowMessage(Query.CurrentObject.ToString);
Query.Next;
end;
finally
Query.Free;
end;
end;Custom File Naming
Override GetObjectFileName to customize file names:
type
TMyXMLFilesAccessor = class(TXMLFilesAccessor)
public
function GetObjectFileName(const AStorageName, AObjectClassName,
AObjectId: string): string; override;
end;
function TMyXMLFilesAccessor.GetObjectFileName(const AStorageName,
AObjectClassName, AObjectId: string): string;
begin
// Custom naming: Year\Month\ClassName_Id.xml
Result := RootFolder +
FormatDateTime('yyyy\mm\', Now) +
AObjectClassName + '_' + AObjectId + DOT_XML_EXT;
// Example: C:\Data\2025\01\TCompany_ABC123.xml
end;Custom Storage Location
Redirect storage to database or cloud:
type
TDatabaseXMLAccessor = class(TXMLFilesAccessor)
protected
function InternalReadInstantObject(const AObject: TInstantObject;
const AStorageName, AObjectId: string;
out AObjectUpdateCount: Integer): Boolean; override;
function InternalWriteInstantObject(const AObject: TInstantObject;
const AStorageName: string;
out AObjectUpdateCount: Integer): Boolean; override;
end;
function TDatabaseXMLAccessor.InternalReadInstantObject(
const AObject: TInstantObject; const AStorageName, AObjectId: string;
out AObjectUpdateCount: Integer): Boolean;
var
XMLContent: string;
Stream: TStringStream;
begin
// Load XML from database
XMLContent := LoadXMLFromDatabase(AStorageName, AObjectId);
Stream := TStringStream.Create(XMLContent, TEncoding.UTF8);
try
InstantReadObject(Stream, sfXML, AObject);
Result := True;
AObjectUpdateCount := 1;
finally
Stream.Free;
end;
end;
function TDatabaseXMLAccessor.InternalWriteInstantObject(
const AObject: TInstantObject; const AStorageName: string;
out AObjectUpdateCount: Integer): Boolean;
var
Stream: TStringStream;
begin
Stream := TStringStream.Create('', TEncoding.UTF8);
try
InstantWriteObject(Stream, sfXML, AObject);
// Save XML to database
SaveXMLToDatabase(AStorageName, AObject.Id, Stream.DataString);
Result := True;
AObjectUpdateCount := 1;
finally
Stream.Free;
end;
end;Custom Load/Save Events
Use events for custom processing:
procedure TMainForm.XMLConnectionCustomLoadXMLFile(const AObject: TInstantObject;
const AObjectId, AFileName: string): Boolean;
begin
// Custom loading logic
if FileExists(AFileName) then
begin
DecryptFile(AFileName); // Decrypt before loading
Result := False; // Let default handler load decrypted file
end
else
Result := False;
end;
procedure TMainForm.XMLConnectionCustomSaveToXMLFile(const AObject: TInstantObject;
const AFileName: string): Boolean;
var
Stream: TStringStream;
begin
// Custom saving logic
Stream := TStringStream.Create('', TEncoding.UTF8);
try
InstantWriteObject(Stream, sfXML, AObject);
Stream.SaveToFile(AFileName);
EncryptFile(AFileName); // Encrypt after saving
Result := True;
finally
Stream.Free;
end;
end;
// Attach events
XMLConnection.OnCustomLoadXMLFile := XMLConnectionCustomLoadXMLFile;
XMLConnection.OnCustomSaveToXMLFile := XMLConnectionCustomSaveToXMLFile;Wildcard Filtering
Filter files by wildcard pattern:
var
Query: TInstantXMLQuery;
begin
Query := XMLConnector.CreateQuery as TInstantXMLQuery;
try
Query.Command := 'SELECT * FROM TCompany';
Query.FilterWildCard := 'TCompany.ABC*.xml'; // Only load ABC* IDs
Query.Open;
// Process filtered results
finally
Query.Free;
end;
end;Folder Organization
Organize by date or category:
type
TDateOrganizedAccessor = class(TXMLFilesAccessor)
public
function GetObjectFileName(const AStorageName, AObjectClassName,
AObjectId: string): string; override;
end;
function TDateOrganizedAccessor.GetObjectFileName(const AStorageName,
AObjectClassName, AObjectId: string): string;
var
YearMonth: string;
begin
YearMonth := FormatDateTime('yyyy-mm', Now);
Result := RootFolder + AStorageName + PathDelim + YearMonth + PathDelim +
AObjectClassName + '.' + AObjectId + '.1' + DOT_XML_EXT;
// Example: C:\Data\Company\2025-01\TCompany.ABC123.1.xml
end;Building XML Database
Create folder structure:
procedure BuildXMLDatabase(const RootFolder: string; Model: TInstantModel);
var
Connector: TInstantXMLConnector;
Scheme: TInstantScheme;
begin
Connector := TInstantXMLConnector.Create(nil);
try
Connector.Connection := TXMLFilesAccessor.Create(nil);
Connector.Connection.RootFolder := RootFolder;
Scheme := Connector.CreateScheme(Model);
try
Connector.BuildDatabase(Scheme);
// Creates root folder only
// Class folders created on first object write
finally
Scheme.Free;
end;
finally
Connector.Free;
end;
end;Batch Import
Import multiple objects:
procedure ImportObjectsFromXML(const SourceFolder: string;
Connector: TInstantXMLConnector);
var
FileList: TStringList;
I: Integer;
FileName, ClassName, ObjectId: string;
Obj: TInstantObject;
FileStream: TFileStream;
begin
FileList := TStringList.Create;
try
// Load all XML files
GlobalLoadFileList(SourceFolder, FileList);
for I := 0 to FileList.Count - 1 do
begin
FileName := SourceFolder + PathDelim + FileList[I];
ClassName := GetFileClassName(FileList[I]);
ObjectId := GetFileId(FileList[I]);
// Create object instance
Obj := InstantFindClass(ClassName).Create(Connector) as TInstantObject;
try
// Load from XML
FileStream := TFileStream.Create(FileName, fmOpenRead);
try
InstantReadObject(FileStream, sfXML, Obj);
finally
FileStream.Free;
end;
// Store to database
Obj.Store;
finally
Obj.Free;
end;
end;
finally
FileList.Free;
end;
end;Backup and Export
Export database to ZIP archive:
uses
System.Zip;
procedure BackupXMLDatabase(const RootFolder, BackupFile: string);
var
ZipFile: TZipFile;
begin
ZipFile := TZipFile.Create;
try
ZipFile.Open(BackupFile, zmWrite);
ZipFile.Add(RootFolder, ''); // Add entire folder
ZipFile.Close;
ShowMessage('Backup created: ' + BackupFile);
finally
ZipFile.Free;
end;
end;
procedure RestoreXMLDatabase(const BackupFile, TargetFolder: string);
var
ZipFile: TZipFile;
begin
ZipFile := TZipFile.Create;
try
ZipFile.Open(BackupFile, zmRead);
ZipFile.ExtractAll(TargetFolder);
ZipFile.Close;
ShowMessage('Database restored to: ' + TargetFolder);
finally
ZipFile.Free;
end;
end;File Naming Convention
Standard Format
ClassName.ObjectId.UpdateCount.xmlComponents:
- ClassName: Business object class name (e.g.,
TCompany) - ObjectId: Unique object identifier (e.g.,
ABC123) - UpdateCount: Object version number (currently always
1) - Extension: Always
.xml
Examples:
TCompany.ABC123.1.xml
TContact.001.1.xml
TProduct.PROD_2025_001.1.xmlParsing File Names
Helper functions to extract information:
function GetFileClassName(const FileName: string): string;
// Returns: 'TCompany' from 'TCompany.ABC123.1.xml'
function GetFileId(const FileName: string): string;
// Returns: 'ABC123' from 'TCompany.ABC123.1.xml'
function GetObjectUpdateCount(const FileName: string): Integer;
// Returns: 1 from 'TCompany.ABC123.1.xml'XML File Format
Example XML File
File: TCompany.ABC123.1.xml
<?xml version="1.0" encoding="UTF-8"?>
<TCompany>
<Class>TCompany</Class>
<Id>ABC123</Id>
<UpdateCount>1</UpdateCount>
<Name>Acme Corporation</Name>
<Address>123 Main St</Address>
<City>Springfield</City>
<Employees>
<TEmployee>
<Class>TEmployee</Class>
<Id>EMP001</Id>
</TEmployee>
<TEmployee>
<Class>TEmployee</Class>
<Id>EMP002</Id>
</TEmployee>
</Employees>
</TCompany>Format characteristics:
- UTF-8 or ISO-8859-1 encoding
- InstantObjects standard XML format (see InstantClasses)
- Embedded objects included inline
- References stored as class/ID pairs
- Parts stored as nested XML
Database Building
TInstantDBBuildXMLCommand
Base class for XML database build commands.
Properties
| Property | Type | Description |
|---|---|---|
| Connector | TInstantXMLConnector | Parent connector |
| Broker | TInstantXMLBroker | Parent broker |
TInstantDBBuildXMLAddTableCommand
Creates storage folder for a class.
procedure InternalExecute; override;Execution:
- Checks root folder exists
- Creates root folder if needed
- Does NOT create class folder (created on first write)
TInstantDBBuildXMLDropTableCommand
Deletes storage folder and all XML files.
procedure InternalExecute; override;Execution:
- Locates class folder
- Deletes all XML files in folder
- Removes folder
Example:
var
Builder: TInstantDBBuilder;
Connector: TInstantXMLConnector;
begin
Builder := TInstantDBBuilder.Create(nil);
try
Builder.Connector := Connector;
Builder.TargetModel := InstantModel1.CurrentModel;
Builder.BuildCommandSequence;
Builder.CommandSequence.Execute;
// Creates root folder structure
finally
Builder.Free;
end;
end;Performance Considerations
Strengths
- Simplicity: No database server required
- Portability: Copy folder = backup/restore
- Human-Readable: XML files can be edited manually
- Version Control: Individual files work well with Git/SVN
- No Installation: Zero configuration
Limitations
Query Performance: All files loaded into memory
- Small datasets (< 10,000 objects): Good performance
- Large datasets (> 100,000 objects): Poor performance
No Transactions: File-based = no ACID guarantees
No Concurrency Control: File locking only
No Server-Side Filtering: WHERE clause applied in memory
No Indexes: Linear scan of files
Optimization Tips
1. Use Wildcard Filtering
Query.FilterWildCard := 'TCompany.2025*.xml'; // Load only 2025 data2. Organize by Folders
// Override GetObjectFileName to organize by year/month
// Limits files scanned per query3. Limit Result Sets
// Use TOP or FIRST in IQL
Query.Command := 'SELECT FIRST 100 * FROM TCompany ORDER BY Name';4. Use Specific Classes
// Don't use ANY keyword for large hierarchies
Query.Command := 'SELECT * FROM TCompany'; // Good
Query.Command := 'SELECT * FROM ANY TCompany'; // Bad (loads all subclasses)5. Retrieve by ID
// Direct retrieval bypasses query
Company := TCompany.Retrieve('ABC123', False, False, Connector);Transaction Support
Important: XML broker does NOT support real transactions.
procedure TInstantXMLConnector.InternalStartTransaction;
begin
{ TODO: Start transaction for Connection }
end;
procedure TInstantXMLConnector.InternalCommitTransaction;
begin
{ TODO: Commit transaction for Connection }
end;
procedure TInstantXMLConnector.InternalRollbackTransaction;
begin
{ TODO: Roll back transaction for Connection }
end;Workaround for transactional behavior:
procedure SaveWithBackup(Obj: TInstantObject);
var
BackupFile: string;
begin
// Manual "transaction" via backup
BackupFile := GetObjectFileName(Obj) + '.bak';
if FileExists(GetObjectFileName(Obj)) then
CopyFile(GetObjectFileName(Obj), BackupFile);
try
Obj.Store;
DeleteFile(BackupFile); // "Commit"
except
if FileExists(BackupFile) then
begin
CopyFile(BackupFile, GetObjectFileName(Obj)); // "Rollback"
DeleteFile(BackupFile);
end;
raise;
end;
end;Best Practices
1. Use for Appropriate Scenarios
✓ Good use cases:
- Prototypes and demos
- Small applications (< 10,000 objects)
- Portable applications
- Configuration storage
- Offline/disconnected scenarios
✗ Poor use cases:
- Large datasets (> 100,000 objects)
- Multi-user applications
- High-concurrency scenarios
- Complex queries
2. Implement Regular Backups
// Schedule regular backups
procedure BackupXMLData;
var
BackupFolder: string;
begin
BackupFolder := Format('Backup_%s', [FormatDateTime('yyyymmdd_hhnnss', Now)]);
CopyDirectory(XMLConnection.RootFolder, BackupFolder);
end;3. Validate XML Files
// Validate XML integrity on startup
procedure ValidateXMLDatabase(const RootFolder: string);
var
FileList: TStringList;
I: Integer;
XMLDoc: IXMLDocument;
begin
FileList := TStringList.Create;
try
GlobalLoadFileList(RootFolder, FileList);
for I := 0 to FileList.Count - 1 do
begin
try
// Attempt to parse XML
XMLDoc := LoadXMLDocument(FileList[I]);
except
on E: Exception do
LogError('Corrupt XML file: ' + FileList[I]);
end;
end;
finally
FileList.Free;
end;
end;4. Use UTF-8 Encoding
// Always use UTF-8 for international characters
XMLConnection.XMLFileFormat := xffUtf8;5. Implement File Locking
// Use exclusive access when modifying
Stream := TFileStream.Create(FileName,
fmOpenReadWrite or fmShareExclusive);6. Monitor Folder Size
// Implement folder size monitoring
procedure CheckDatabaseSize(const RootFolder: string);
var
Size: Int64;
begin
Size := GetFolderSize(RootFolder);
if Size > 100 * 1024 * 1024 then // 100 MB
ShowWarning('Database size exceeds 100 MB. Consider migrating to SQL.');
end;Troubleshooting
Files Not Found
Problem: LocateInstantObject returns False.
Diagnosis:
// Check file existence
FileName := XMLConnection.GetObjectFileName('Company', 'TCompany', 'ABC123');
if not FileExists(FileName) then
ShowMessage('File not found: ' + FileName);Solutions:
- Verify
RootFolderis correct - Check folder permissions
- Verify object was stored successfully
Corrupt XML Files
Problem: Exception when loading objects.
Diagnosis:
// Try loading XML manually
var
XMLDoc: IXMLDocument;
begin
try
XMLDoc := LoadXMLDocument(FileName);
except
on E: Exception do
ShowMessage('XML Error: ' + E.Message);
end;
end;Solutions:
- Restore from backup
- Manually edit XML to fix syntax
- Delete and recreate object
Slow Query Performance
Problem: Queries take long time.
Diagnosis:
// Count files being loaded
FileCount := GetFileCount(XMLConnection.RootFolder);
ShowMessage(Format('Loading %d files', [FileCount]));Solutions:
- Use wildcard filtering
- Organize into subfolders
- Limit result sets with FIRST/TOP
- Consider migrating to SQL broker
Encoding Issues
Problem: Special characters corrupted.
Solution:
// Ensure UTF-8 encoding
XMLConnection.XMLFileFormat := xffUtf8;
// Verify file encoding externallyConcurrency Conflicts
Problem: Multiple users overwriting changes.
Solution:
// Implement application-level locking
// Or migrate to SQL broker with real transaction supportMigration from/to XML Broker
Export from SQL to XML
procedure ExportToXML(SourceConnector, TargetXMLConnector: TInstantConnector);
var
Query: TInstantQuery;
Obj, NewObj: TInstantObject;
begin
Query := SourceConnector.CreateQuery;
try
Query.Command := 'SELECT * FROM ANY TInstantObject';
Query.Open;
while not Query.EOF do
begin
Obj := Query.CurrentObject as TInstantObject;
// Create copy in XML database
NewObj := TInstantObjectClass(Obj.ClassType).Create(TargetXMLConnector);
try
NewObj.Assign(Obj);
NewObj.Store;
finally
NewObj.Free;
end;
Query.Next;
end;
finally
Query.Free;
end;
end;Import from XML to SQL
procedure ImportFromXML(SourceXMLConnector, TargetConnector: TInstantConnector);
var
FileList: TStringList;
I: Integer;
ClassName, ObjectId: string;
Obj, NewObj: TInstantObject;
begin
FileList := TStringList.Create;
try
(SourceXMLConnector.Connection as TXMLFilesAccessor).LoadFileList(
FileList, GetAllStorageNames);
for I := 0 to FileList.Count - 1 do
begin
ClassName := GetFileClassName(FileList[I]);
ObjectId := GetFileId(FileList[I]);
// Load from XML
Obj := InstantFindClass(ClassName).Create(SourceXMLConnector);
try
Obj.Id := ObjectId;
Obj.Refresh;
// Store to SQL
NewObj := TInstantObjectClass(Obj.ClassType).Create(TargetConnector);
try
NewObj.Assign(Obj);
NewObj.Store;
finally
NewObj.Free;
end;
finally
Obj.Free;
end;
end;
finally
FileList.Free;
end;
end;See Also
- InstantBrokers - Broker architecture
- InstantClasses - XML serialization
- InstantPersistence - Persistence infrastructure
- InstantCommand - IQL query language
Source Code
File: InstantXML.pasLocation: Source/Brokers/XML/
Summary
The InstantXML broker provides file-based XML persistence ideal for small applications, prototyping, and portable scenarios. Each object is stored as a separate XML file using the naming convention ClassName.ObjectId.UpdateCount.xml, organized into folders by storage name.
Key advantages:
- No database server required
- Human-readable format
- Simple backup (copy folder)
- Zero configuration
Key limitations:
- Poor performance for large datasets (all files loaded into memory)
- No real transactions
- Limited concurrency support
- No server-side filtering
Best for: Prototypes, small applications (< 10,000 objects), portable apps, offline scenarios. Not recommended for: Large datasets, multi-user applications, high-concurrency scenarios.
