Fixed: safe NodeValue to String conversion

Fixed: NodeValue getter would treat it as a ChildNode instead (as did attributes)
Changed: use of generic collections instead of typecasts
This commit is contained in:
Mark van Renswoude 2014-10-28 14:22:41 +00:00
parent f3d8ef6968
commit 66dbd1738a
4 changed files with 89 additions and 125 deletions

View File

@ -2,11 +2,9 @@ unit DelphiXMLDataBindingGenerator;
interface
uses
Classes,
Contnrs,
XMLSchema,
X2UtHashes,
System.Classes,
System.Generics.Collections,
Xml.XMLSchema,
DelphiXMLDataBindingResources,
XMLDataBindingGenerator,
@ -16,22 +14,12 @@ uses
type
TGetFileNameEvent = procedure(Sender: TObject; const SchemaName: String; var Path, FileName: String) of object;
TXMLSchemaList = class(TObjectList)
private
function GetItem(Index: Integer): TXMLDataBindingSchema;
procedure SetItem(Index: Integer; const Value: TXMLDataBindingSchema);
public
constructor Create;
property Items[Index: Integer]: TXMLDataBindingSchema read GetItem write SetItem; default;
end;
TXMLSchemaList = TList<TXMLDataBindingSchema>;
TDelphiXMLDataBindingGenerator = class(TXMLDataBindingGenerator)
private
FProcessedItems: TX2OIHash;
FUnitNames: TX2OSHash;
FProcessedItems: TList<TXMLDataBindingInterface>;
FUnitNames: TDictionary<TXMLDataBindingSchema, String>;
FOnGetFileName: TGetFileNameEvent;
protected
@ -73,13 +61,13 @@ type
procedure WriteEnumerator(AWriter: TNamedFormatWriter; AItem: TXMLDataBindingInterface; ASection: TDelphiXMLSection);
function GetDelphiNodeType(AProperty: TXMLDataBindingProperty): TDelphiNodeType;
function GetDelphiElementType(AProperty: TXMLDataBindingProperty): TDelphiElementType;
function GetDelphiElementType(ANodeType: TDelphiNodeType): TDelphiElementType;
function DataTypeConversion(const ADestination, ASource: String; ADataType: IXMLTypeDef; AAccessor: TDelphiAccessor; ANodeType: TDelphiNodeType; const ATargetNamespace: string; const ALinesBefore: String = ''): String;
function XMLToNativeDataType(const ADestination, ASource: String; ADataType: IXMLTypeDef; ANodeType: TDelphiNodeType; const ATargetNamespace: string; const ALinesBefore: String = ''): String;
function NativeDataTypeToXML(const ADestination, ASource: String; ADataType: IXMLTypeDef; ANodeType: TDelphiNodeType; const ATargetNamespace: string; const ALinesBefore: String = ''): String;
property ProcessedItems: TX2OIHash read FProcessedItems;
property UnitNames: TX2OSHash read FUnitNames;
property ProcessedItems: TList<TXMLDataBindingInterface> read FProcessedItems;
property UnitNames: TDictionary<TXMLDataBindingSchema, String> read FUnitNames;
public
property OnGetFileName: TGetFileNameEvent read FOnGetFileName write FOnGetFileName;
end;
@ -116,12 +104,12 @@ begin
otMultiple:
begin
FUnitNames := TX2OSHash.Create;
FUnitNames := TDictionary<TXMLDataBindingSchema, String>.Create;
try
for schemaIndex := 0 to Pred(SchemaCount) do
begin
schema := Schemas[schemaIndex];
FUnitNames[schema] := DoGetFileName(schema.SchemaName);
schema := Schemas[schemaIndex];
FUnitNames.Add(schema, DoGetFileName(schema.SchemaName));
end;
for schemaIndex := 0 to Pred(SchemaCount) do
@ -164,7 +152,7 @@ begin
['UsesClause', usesClause]);
WriteSection(unitWriter, dxsForward, ASchemaList);
FProcessedItems := TX2OIHash.Create;
FProcessedItems := TList<TXMLDataBindingInterface>.Create;
try
FProcessedItems.Clear;
WriteSection(unitWriter, dxsInterface, ASchemaList);
@ -194,13 +182,13 @@ end;
function TDelphiXMLDataBindingGenerator.GenerateUsesClause(ASchemaList: TXMLSchemaList): String;
var
includedSchemas: TObjectList;
includedSchemas: TList<TXMLDataBindingSchema>;
procedure AddSchema(ASchema: TXMLDataBindingSchema);
begin
if Assigned(ASchema) and
(includedSchemas.IndexOf(ASchema) = -1) and
(ASchemaList.IndexOf(ASchema) = -1) then
(not includedSchemas.Contains(ASchema)) and
(not ASchemaList.Contains(ASchema)) then
includedSchemas.Add(ASchema);
end;
@ -212,12 +200,11 @@ var
interfaceItem: TXMLDataBindingInterface;
propertyIndex: Integer;
propertyItem: TXMLDataBindingProperty;
includeIndex: Integer;
begin
Result := '';
includedSchemas := TObjectList.Create(False);
includedSchemas := TList<TXMLDataBindingSchema>.Create;
try
{ Determine which items are used }
for schemaIndex := 0 to Pred(ASchemaList.Count) do
@ -247,11 +234,8 @@ begin
{ Build uses clause }
if includedSchemas.Count > 0 then
begin
for includeIndex := 0 to Pred(includedSchemas.Count) do
begin
schema := TXMLDataBindingSchema(includedSchemas[includeIndex]);
for schema in includedSchemas do
Result := Result + ' ' + ChangeFileExt(ExtractFileName(FUnitNames[schema]), '') + ',' + CrLf;
end;
Result := Result + CrLf;
end;
@ -525,7 +509,7 @@ end;
procedure TDelphiXMLDataBindingGenerator.WriteEnumerationConversions(AWriter: TNamedFormatWriter; ASection: TDelphiXMLSection; ASchemaList: TXMLSchemaList);
var
enumerations: TObjectList;
enumerations: TList<TXMLDataBindingItem>;
schemaIndex: Integer;
schema: TXMLDataBindingSchema;
itemIndex: Integer;
@ -539,7 +523,7 @@ begin
Exit;
enumerations := TObjectList.Create(False);
enumerations := TList<TXMLDataBindingItem>.Create;
try
for schemaIndex := 0 to Pred(ASchemaList.Count) do
begin
@ -623,7 +607,8 @@ begin
{ In ye olde days this is where we checked if XMLDataBindingUtils was required. With the
introduction of the IXSDValidate, this is practically always the case. }
AWriter.WriteLine('uses');
AWriter.WriteLine(' SysUtils;');
AWriter.WriteLine(' SysUtils,');
AWriter.WriteLine(' Variants;');
AWriter.WriteLine;
end;
@ -677,13 +662,13 @@ begin
begin
{ Ensure the base item is completely defined first, Delphi doesn't allow
inheritance with just a forward declaration. }
if ProcessedItems.Exists(AItem) then
if ProcessedItems.Contains(AItem) then
exit;
if Assigned(AItem.BaseItem) then
WriteSchemaInterface(AWriter, AItem.BaseItem, ASection);
ProcessedItems[AItem] := 1;
ProcessedItems.Add(AItem);
end;
@ -1140,7 +1125,7 @@ var
fieldName: String;
writeStream: Boolean;
typeMapping: TTypeMapping;
elementType: TDelphiElementType;
nodeType: TDelphiNodeType;
begin
Result := False;
@ -1290,23 +1275,23 @@ begin
case AMember of
dxmPropertyGet:
begin
elementType := GetDelphiElementType(AProperty);
nodeType := GetDelphiNodeType(AProperty);
WriteNewLine;
if writeOptional then
if AProperty.IsAttribute then
sourceCode.Add(PropertyImplMethodGetOptionalAttr)
else
sourceCode.Add(PropertyImplMethodGetOptional[elementType]);
sourceCode.Add(PropertyImplMethodGetOptional[GetDelphiElementType(nodeType)]);
if writeNil then
sourceCode.Add(PropertyImplMethodGetNil[elementType]);
sourceCode.Add(PropertyImplMethodGetNil[GetDelphiElementType(nodeType)]);
if writeTextProp then
if AProperty.IsAttribute then
sourceCode.Add(PropertyImplMethodGetTextAttr)
else
sourceCode.Add(PropertyImplMethodGetText[elementType]);
sourceCode.Add(PropertyImplMethodGetText[GetDelphiElementType(nodeType)]);
sourceCode.Add('function TXML%<Name>:s.Get%<PropertyName>:s: %<DataType>:s;');
@ -1321,7 +1306,7 @@ begin
sourceCode.Add(XMLToNativeDataType('Result',
'%<PropertySourceName>:s',
TXMLDataBindingSimpleProperty(AProperty).DataType,
elementType,
nodeType,
AProperty.TargetNamespace));
ptItem:
@ -1366,17 +1351,17 @@ begin
dxmPropertySet:
if not IsReadOnly(AProperty) then
begin
elementType := GetDelphiElementType(AProperty);
nodeType := GetDelphiNodeType(AProperty);
WriteNewLine;
if writeNil then
sourceCode.Add(PropertyImplMethodSetNil[elementType]);
sourceCode.Add(PropertyImplMethodSetNil[GetDelphiElementType(nodeType)]);
if writeTextProp then
if AProperty.IsAttribute then
sourceCode.Add(PropertyImplMethodSetTextAttr)
else
sourceCode.Add(PropertyImplMethodSetText[elementType]);
sourceCode.Add(PropertyImplMethodSetText[GetDelphiElementType(nodeType)]);
sourceCode.Add('procedure TXML%<Name>:s.Set%<PropertyName>:s(const Value: %<DataType>:s);');
value := '%<PropertySourceName>:s';
@ -1384,7 +1369,7 @@ begin
if Assigned(propertyItem) and (propertyItem.ItemType = itEnumeration) then
begin
sourceCode.Add(NativeDataTypeToXML(value, '%<PropertyItemName>:sValues[Value]', nil,
elementType,
nodeType,
AProperty.TargetNamespace));
end else
begin
@ -1393,7 +1378,7 @@ begin
sourceCode.Add(NativeDataTypeToXML(value, 'Value',
TXMLDataBindingSimpleProperty(AProperty).DataType,
elementType,
nodeType,
AProperty.TargetNamespace));
end;
@ -1403,11 +1388,11 @@ begin
dxmPropertyMethods:
if writeStream then
begin
elementType := GetDelphiElementType(AProperty);
sourceCode.Add(PropertyImplMethodLoadFromStream[elementType]);
sourceCode.Add(PropertyImplMethodLoadFromFile[elementType]);
sourceCode.Add(PropertyImplMethodSaveToStream[elementType]);
sourceCode.Add(PropertyImplMethodSaveToFile[elementType]);
nodeType := GetDelphiElementType(GetDelphiNodeType(AProperty));
sourceCode.Add(PropertyImplMethodLoadFromStream[nodeType]);
sourceCode.Add(PropertyImplMethodLoadFromFile[nodeType]);
sourceCode.Add(PropertyImplMethodSaveToStream[nodeType]);
sourceCode.Add(PropertyImplMethodSaveToFile[nodeType]);
end;
end;
end;
@ -1691,10 +1676,11 @@ begin
end;
function TDelphiXMLDataBindingGenerator.GetDelphiElementType(AProperty: TXMLDataBindingProperty): TDelphiElementType;
function TDelphiXMLDataBindingGenerator.GetDelphiElementType(ANodeType: TDelphiNodeType): TDelphiElementType;
begin
Result := GetDelphiNodeType(AProperty);
if Result <> dntElementNS then
if ANodeType = dntElementNS then
Result := dntElementNS
else
Result := dntElement;
end;
@ -1783,25 +1769,6 @@ begin
end;
end;
{ TXMLSchemaList }
constructor TXMLSchemaList.Create;
begin
inherited Create(False);
end;
function TXMLSchemaList.GetItem(Index: Integer): TXMLDataBindingSchema;
begin
Result := TXMLDataBindingSchema(inherited GetItem(Index));
end;
procedure TXMLSchemaList.SetItem(Index: Integer; const Value: TXMLDataBindingSchema);
begin
inherited SetItem(Index, Value);
end;
end.

View File

@ -509,7 +509,7 @@ const
{ tcDateTime } ' %<Destination>:s := XMLToDateTime(GetNodeValue, xdtDateTime);',
{ tcDate } ' %<Destination>:s := XMLToDateTime(GetNodeValue, xdtDate);',
{ tcTime } ' %<Destination>:s := XMLToDateTime(GetNodeValue, xdtTime);',
{ tcString } ' %<Destination>:s := GetNodeValue;',
{ tcString } ' %<Destination>:s := VarToStr(GetNodeValue);',
{ tcBase64 } ' %<Destination>:s := Base64Decode(Trim(GetNodeValue));',
{ tcNode } ''
),

View File

@ -4,9 +4,9 @@ unit XMLDataBindingGenerator;
interface
uses
Classes,
Contnrs,
XMLSchema;
System.Classes,
System.Generics.Collections,
Xml.XMLSchema;
type
TXMLDataBindingSchema = class;
@ -40,7 +40,7 @@ type
FOutputType: TXMLDataBindingOutputType;
FSourceFileName: String;
FSchemas: TObjectList;
FSchemas: TObjectList<TXMLDataBindingSchema>;
FOnPostProcessItem: TXMLDataBindingPostProcessItemEvent;
@ -121,8 +121,8 @@ type
TXMLDataBindingSchema = class(TXMLDataBindingGeneratorItem)
private
FIncludes: TObjectList;
FItems: TObjectList;
FIncludes: TObjectList<TXMLDataBindingSchema>;
FItems: TObjectList<TXMLDataBindingItem>;
FItemsGenerated: Boolean;
FSchemaDef: IXMLSchemaDef;
FSchemaName: String;
@ -199,7 +199,7 @@ type
private
FInterfaceType: TXMLDataBindingInterfaceType;
FIsSequence: Boolean;
FProperties: TObjectList;
FProperties: TObjectList<TXMLDataBindingProperty>;
FBaseName: String;
FBaseItem: TXMLDataBindingInterface;
@ -242,7 +242,7 @@ type
TXMLDataBindingEnumeration = class(TXMLDataBindingItem)
private
FMembers: TObjectList;
FMembers: TObjectList<TXMLDataBindingEnumerationMember>;
FIsAttribute: Boolean;
function GetMemberCount: Integer;
@ -355,14 +355,12 @@ type
implementation
uses
SysUtils,
Variants,
Windows,
XMLDoc,
XMLIntf,
XMLSchemaTags,
X2UtHashes;
System.SysUtils,
System.Variants,
Winapi.Windows,
Xml.XMLDoc,
Xml.XMLIntf,
Xml.XMLSchemaTags;
const
@ -388,7 +386,7 @@ begin
inherited Create;
FIncludePaths := TStringList.Create;
FSchemas := TObjectList.Create(True);
FSchemas := TObjectList<TXMLDataBindingSchema>.Create(True);
with TStringList(FIncludePaths) do
begin
@ -1336,25 +1334,28 @@ end;
procedure TXMLDataBindingGenerator.ResolveNameConflicts;
type
TItemNamesDictionary = TObjectDictionary<String, TObjectList<TXMLDataBindingItem>>;
var
itemNames: TX2SOHash;
itemNames: TItemNamesDictionary;
procedure AddItem(AItem: TXMLDataBindingItem);
var
hashName: String;
items: TObjectList;
items: TObjectList<TXMLDataBindingItem>;
begin
{ LowerCase because XML is case-sensitive, but Delphi isn't. }
hashName := LowerCase(AItem.Name);
if not itemNames.Exists(hashName) then
if not itemNames.ContainsKey(hashName) then
begin
items := TObjectList.Create(False);
itemNames[hashName] := items;
items := TObjectList<TXMLDataBindingItem>.Create(False);
itemNames.Add(hashName, items);
end else
items := TObjectList(itemNames[hashName]);
items := itemNames[hashName];
items.Add(AItem);
end;
@ -1397,14 +1398,14 @@ var
schemaIndex: Integer;
schema: TXMLDataBindingSchema;
itemIndex: Integer;
items: TObjectList;
items: TObjectList<TXMLDataBindingItem>;
item: TXMLDataBindingItem;
depth: Integer;
newName: String;
resolved: Boolean;
begin
itemNames := TX2SOHash.Create(True);
itemNames := TItemNamesDictionary.Create([doOwnsValues]);
try
{ Gather names }
for schemaIndex := 0 to Pred(SchemaCount) do
@ -1413,7 +1414,7 @@ begin
for itemIndex := 0 to Pred(schema.ItemCount) do
begin
item := schema.Items[itemIndex];
item := schema.Items[itemIndex];
if item.ItemType in [itInterface, itEnumeration] then
AddItem(item);
@ -1422,25 +1423,21 @@ begin
{ Find conflicts }
itemNames.First;
while itemNames.Next do
for items in itemNames.Values do
begin
items := TObjectList(itemNames.CurrentValue);
if items.Count > 1 then
begin
{ Attempt to rename items }
for itemIndex := Pred(items.Count) downto 0 do
begin
item := TXMLDataBindingItem(items[itemIndex]);
item := items[itemIndex];
newName := item.Name;
resolved := False;
depth := 1;
while ResolveItemNameConflict(item, depth, newName) do
begin
if not itemNames.Exists(newName) then
if not itemNames.ContainsKey(newName) then
begin
resolved := True;
break;
@ -1490,7 +1487,7 @@ var
memberIndex: Integer;
propertyIndex: Integer;
propertyItem: TXMLDataBindingProperty;
repeatingItems: TObjectList;
repeatingItems: TObjectList<TXMLDataBindingProperty>;
typedSchemaItem: IXMLTypedSchemaItem;
begin
@ -1537,7 +1534,7 @@ begin
interfaceItem := TXMLDataBindingInterface(AItem);
interfaceItem.CollectionItem := nil;
repeatingItems := TObjectList.Create(False);
repeatingItems := TObjectList<TXMLDataBindingProperty>.Create(False);
try
for propertyIndex := 0 to Pred(interfaceItem.PropertyCount) do
if interfaceItem.Properties[propertyIndex].IsRepeating then
@ -1549,7 +1546,7 @@ begin
(not Assigned(interfaceItem.BaseItem)) then
begin
{ Single repeating child, the item itself is a collection parent }
interfaceItem.CollectionItem := TXMLDataBindingProperty(repeatingItems[0]);
interfaceItem.CollectionItem := repeatingItems[0];
end else
begin
{ Multiple repeating children or this interface is a descendant,
@ -1601,7 +1598,7 @@ end;
function TXMLDataBindingGenerator.GetSchemas(Index: Integer): TXMLDataBindingSchema;
begin
Result := TXMLDataBindingSchema(FSchemas[Index]);
Result := FSchemas[Index];
end;
@ -1624,8 +1621,8 @@ constructor TXMLDataBindingSchema.Create(AOwner: TXMLDataBindingGenerator);
begin
inherited Create(AOwner);
FIncludes := TObjectList.Create(False);
FItems := TObjectList.Create(True);
FIncludes := TObjectList<TXMLDataBindingSchema>.Create(False);
FItems := TObjectList<TXMLDataBindingItem>.Create(True);
end;
@ -1696,7 +1693,7 @@ end;
function TXMLDataBindingSchema.GetIncludes(Index: Integer): TXMLDataBindingSchema;
begin
Result := TXMLDataBindingSchema(FIncludes[Index]);
Result := FIncludes[Index];
end;
@ -1708,7 +1705,7 @@ end;
function TXMLDataBindingSchema.GetItems(Index: Integer): TXMLDataBindingItem;
begin
Result := TXMLDataBindingItem(FItems[Index]);
Result := FItems[Index];
end;
@ -1775,7 +1772,7 @@ var
begin
inherited Create(AOwner, ASchemaItem, AName);
FProperties := TObjectList.Create(True);
FProperties := TObjectList<TXMLDataBindingProperty>.Create(True);
FInterfaceType := GetInterfaceType(SchemaItem);
FIsSequence := False;
@ -1821,7 +1818,7 @@ begin
propertyItem := Properties[propertyIndex];
if propertyItem = AOldItem then
FProperties.Extract(AOldItem)
FProperties.Extract(propertyItem)
else
begin
if (AOldItem.ItemType = itSimpleTypeAlias) and
@ -1907,7 +1904,7 @@ end;
function TXMLDataBindingInterface.GetProperties(Index: Integer): TXMLDataBindingProperty;
begin
Result := TXMLDataBindingProperty(FProperties[Index]);
Result := FProperties[Index];
end;
@ -1934,7 +1931,7 @@ var
begin
inherited Create(AOwner, ASchemaItem, AName);
FMembers := TObjectList.Create;
FMembers := TObjectList<TXMLDataBindingEnumerationMember>.Create;
FIsAttribute := AIsAttribute;
for memberIndex := 0 to Pred(AEnumerations.Count) do
@ -1964,7 +1961,7 @@ end;
function TXMLDataBindingEnumeration.GetMembers(Index: Integer): TXMLDataBindingEnumerationMember;
begin
Result := TXMLDataBindingEnumerationMember(FMembers[Index]);
Result := FMembers[Index];
end;

View File

@ -9,7 +9,7 @@
<ProjectVersion>13.4</ProjectVersion>
<Base>True</Base>
<Config Condition="'$(Config)'==''">Build</Config>
<Platform Condition="'$(Platform)'==''">Win64</Platform>
<Platform Condition="'$(Platform)'==''">Win32</Platform>
<TargetedPlatforms>3</TargetedPlatforms>
<AppType>Application</AppType>
</PropertyGroup>