Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Prevent duplicate field names #59

Merged
merged 3 commits into from
Sep 19, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 1 addition & 1 deletion src/Directory.Build.props
Original file line number Diff line number Diff line change
Expand Up @@ -99,7 +99,7 @@

<ItemGroup>
<!-- SourceLink adds stuff to let debuggers step into our code. -->
<PackageReference Include="Microsoft.SourceLink.GitHub" Version="1.0.0" PrivateAssets="All" />
<PackageReference Include="Microsoft.SourceLink.GitHub" Version="8.0.0" PrivateAssets="All" />
</ItemGroup>

</Project>
5 changes: 5 additions & 0 deletions src/NetTopologySuite.IO.Esri.Shapefile/Dbf/DbfReader.cs
Original file line number Diff line number Diff line change
Expand Up @@ -121,10 +121,15 @@ private void Initialize(Stream stream, Encoding encoding = null)

Buffer.AssignFrom(DbfStream, fieldsHeaderSize);
Fields = new DbfFieldCollection(fieldCount);
var duplicates = new Dictionary<string, int>();
for (int i = 0; i < fieldCount; i++)
{
var field = Buffer.ReadDbaseFieldDescriptor(Encoding);
string originalName = field.Name;
duplicates.TryGetValue(originalName, out int duplicateCount);
field.DuplicateCount = duplicateCount;
Fields.Add(field);
duplicates[originalName] = ++duplicateCount;
//Binary.TraceToConsole("Field Header: " + Fields[Fields.Count -1].Name, i * Dbf.FieldDescriptorSize, Dbf.FieldDescriptorSize);
}

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -84,8 +84,7 @@ public static Encoding ReadDbfEncoding(this Stream stream)
public static void WriteDbaseFieldDescriptor(this Stream stream, DbfField field, Encoding encoding)
{
encoding = encoding ?? Dbf.DefaultEncoding;
var name = field.Name.PadRight(Dbf.MaxFieldNameLength, char.MinValue); // Field name must have empty space zero-filled

var name = field.OriginalName.PadRight(Dbf.MaxFieldNameLength, char.MinValue); // Field name must have empty space zero-filled

stream.WriteString(name, Dbf.MaxFieldNameLength, encoding);
stream.WriteNullBytes(1);
Expand Down
23 changes: 15 additions & 8 deletions src/NetTopologySuite.IO.Esri.Shapefile/Dbf/Fields/DbfField.cs
Original file line number Diff line number Diff line change
Expand Up @@ -15,10 +15,22 @@ public abstract class DbfField
{
// TODO: Spit DbfField into DbfFieldDefinition (Without Value property) and DbfFieldValue

/// <summary>
/// Original field name
/// </summary>
internal string OriginalName { get; }

/// <summary>
/// Field Name.
/// </summary>
public string Name { get; }
public string Name
{
get
{
string suffix = DuplicateCount > 0 ? $"_{DuplicateCount}" : string.Empty;
return $"{OriginalName}{suffix}";
}
}

/// <summary>
/// Field Type.
Expand Down Expand Up @@ -75,17 +87,12 @@ internal DbfField(string name, DbfType type, int length, int precision)
throw new ArgumentException($"Ivalid dBASE field precision: {precision}.", nameof(precision));
}

Name = name;
OriginalName = name;
FieldType = type;
Length = length;
NumericScale = precision;
}

private bool IsValidFieldNameChar(char c)
{
return (c >= 'a' && c <= 'z') || (c >= 'A' && c <= 'Z') || c == '_' || (c >= '0' && c <= '9');
}

/// <inheritdoc/>
public override string ToString()
{
Expand Down Expand Up @@ -113,7 +120,7 @@ internal Exception GetFieldValueError(object value, string additionalDescription
/// </summary>
public virtual bool IsNull => Value == null;


internal int DuplicateCount { get; set; }

internal static readonly IAttributesTable EmptyFieldValues = new AttributesTable();

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -59,6 +59,8 @@ IEnumerator IEnumerable.GetEnumerator()

internal void Add(DbfField field)
{
if (FieldDictionary.ContainsKey(field.Name))
throw new ArgumentException($"Field with name '{field.Name}' already defined.");
Fields.Add(field);
FieldDictionary.Add(field.Name, field);
}
Expand Down
4 changes: 2 additions & 2 deletions test/Directory.Build.props
Original file line number Diff line number Diff line change
Expand Up @@ -5,8 +5,8 @@

<ItemGroup>
<PackageReference Include="nunit" Version="3.12.0" />
<PackageReference Include="NUnit3TestAdapter" Version="3.16.1" />
<PackageReference Include="Microsoft.NET.Test.Sdk" Version="16.5.0" />
<PackageReference Include="NUnit3TestAdapter" Version="4.6.0" />
<PackageReference Include="Microsoft.NET.Test.Sdk" Version="17.11.1" />
</ItemGroup>

</Project>
22 changes: 22 additions & 0 deletions test/NetTopologySuite.IO.Esri.Test/Issues/Issue046.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,22 @@
using NetTopologySuite.IO.Esri.Dbf;
using NUnit.Framework;
using System.Collections.Generic;

namespace NetTopologySuite.IO.Esri.Test.Issues
{
internal class Issue046
{
[Test]
public void TestNoDuplicateColumnName()
{
using var dbfReader = new DbfReader(TestShapefiles.PathTo("Issues/046/Antragsschläge 2024_POLYGONE.dbf"));
var dbfFields = dbfReader.Fields;
var fieldNames = new HashSet<string>();
for (int i = 0; i < dbfFields.Count; i++)
{
Assert.That(fieldNames.Contains(dbfFields[i].Name), Is.False);
fieldNames.Add(dbfFields[i].Name);
}
}
}
}
Binary file not shown.