Skip to content

Commit fe8099b

Browse files
committed
GeoJSON Handle ID properly (NetTopologySuite#83)
1 parent 213696b commit fe8099b

File tree

8 files changed

+135
-1
lines changed

8 files changed

+135
-1
lines changed

NetTopologySuite.IO/NetTopologySuite.IO.GeoJSON/Converters/AttributesTableConverter.cs

+3
Original file line numberDiff line numberDiff line change
@@ -29,6 +29,9 @@ public override void WriteJson(JsonWriter writer, object value, JsonSerializer s
2929
string[] names = attributes.GetNames();
3030
foreach (string name in names)
3131
{
32+
// skip id
33+
if (name == "id") continue;
34+
3235
writer.WritePropertyName(name);
3336
object val = attributes[name];
3437
serializer.Serialize(writer, val);

NetTopologySuite.IO/NetTopologySuite.IO.GeoJSON/Converters/FeatureConverter.cs

+16
Original file line numberDiff line numberDiff line change
@@ -28,12 +28,28 @@ public override void WriteJson(JsonWriter writer, object value, JsonSerializer s
2828
return;
2929

3030
writer.WriteStartObject();
31+
32+
// type
3133
writer.WritePropertyName("type");
3234
writer.WriteValue("Feature");
35+
36+
// Add the id here if present in attributes.
37+
// It will be skipped in serialization of properties
38+
if (feature.Attributes.Exists("id"))
39+
{
40+
var id = feature.Attributes["id"];
41+
writer.WritePropertyName("id");
42+
serializer.Serialize(writer, id);
43+
}
44+
45+
// geometry
3346
writer.WritePropertyName("geometry");
3447
serializer.Serialize(writer, feature.Geometry);
48+
49+
// properties
3550
writer.WritePropertyName("properties");
3651
serializer.Serialize(writer, feature.Attributes);
52+
3753
writer.WriteEndObject();
3854
}
3955

Original file line numberDiff line numberDiff line change
@@ -0,0 +1,54 @@
1+
using System.IO;
2+
using System.Text;
3+
using NetTopologySuite.Features;
4+
using Newtonsoft.Json;
5+
using Newtonsoft.Json.Linq;
6+
using NUnit.Framework;
7+
8+
namespace NetTopologySuite.IO.Tests.GeoJSON
9+
{
10+
[Category("GitHub")]
11+
[TestFixture]
12+
public class GitHubIssues
13+
{
14+
[Test(Description = "Testcase for Issue 83") ]
15+
public void TestIssue83()
16+
{
17+
var geoJson = "{ \"type\": \"Feature\", " +
18+
"\"geometry\": { \"type\": \"Point\", \"coordinates\": [10.0, 60.0] }, " +
19+
"\"id\": 1, " +
20+
"\"properties\": { \"Name\": \"test\" } }";
21+
22+
var s = new GeoJsonSerializer();
23+
Feature f = null;
24+
Assert.DoesNotThrow( () =>
25+
f = s.Deserialize<Feature>(new JsonTextReader(new StringReader(geoJson)))
26+
);
27+
28+
Assert.IsNotNull(f, "f != null");
29+
Assert.IsTrue(f.HasID(), "f.HasID()");
30+
Assert.AreEqual(1, f.ID(), "f.ID != 1");
31+
32+
var sb = new StringBuilder();
33+
var tw = new JsonTextWriter(new StringWriter(sb));
34+
s.Serialize(tw, f);
35+
var geoJsonRes = sb.ToString();
36+
37+
CompareJson(geoJson, geoJsonRes);
38+
}
39+
40+
public void CompareJson(string expectedJson, string json)
41+
{
42+
var e = JToken.Parse(expectedJson);
43+
var j = JToken.Parse(json);
44+
45+
if (!JToken.DeepEquals(e, j))
46+
{
47+
var res = string.Format("The json's do not match:\n1: {0}\n2:{1}",
48+
expectedJson, json);
49+
Assert.IsTrue(false, res);
50+
}
51+
52+
}
53+
}
54+
}

NetTopologySuite.IO/NetTopologySuite.IO.Tests/NetTopologySuite.IO.Tests.csproj

+1-1
Original file line numberDiff line numberDiff line change
@@ -16,7 +16,6 @@
1616
<FileAlignment>512</FileAlignment>
1717
<TargetFrameworkProfile>Client</TargetFrameworkProfile>
1818
<SolutionDir Condition="$(SolutionDir) == '' Or $(SolutionDir) == '*Undefined*'">..\..\</SolutionDir>
19-
2019
</PropertyGroup>
2120
<PropertyGroup Condition=" '$(Configuration)|$(Platform)' == 'Debug|AnyCPU' ">
2221
<DebugSymbols>true</DebugSymbols>
@@ -84,6 +83,7 @@
8483
<Compile Include="GeoJSON\FeatureConverterTest.cs" />
8584
<Compile Include="GeoJSON\GeoJsonSerializerTest.cs" />
8685
<Compile Include="GeoJSON\GeoJsonWriterTest.cs" />
86+
<Compile Include="GeoJSON\GitHubIssues.cs" />
8787
<Compile Include="GeoJSON\Issue148.cs" />
8888
<Compile Include="GeoJSON\Issue16Fixture.cs" />
8989
<Compile Include="GeoJSON\Issue32Fixture.cs" />
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,48 @@
1+
using System;
2+
3+
namespace NetTopologySuite.Features
4+
{
5+
/// <summary>
6+
/// Extension methods for <see cref="IFeature"/>s.
7+
/// </summary>
8+
public static class FeatureExtensions
9+
{
10+
static FeatureExtensions()
11+
{
12+
// According to GeoJSON name of the feature's identifier
13+
IdAttributeName = "id";
14+
}
15+
16+
/// <summary>
17+
/// Gets or sets a name that is used to retrieve the ID of a feature from the attribute table
18+
/// </summary>
19+
public static string IdAttributeName { get; set; }
20+
21+
/// <summary>
22+
/// Function to get a feature's ID
23+
/// </summary>
24+
/// <param name="feature">The feature</param>
25+
/// <returns>The feature's ID if one has been assigned, otherwise <value>null</value></returns>
26+
/// <exception cref="ArgumentNullException">Thrown, if <paramref name="feature"/> is <valu>null</valu></exception>
27+
public static object ID(this IFeature feature)
28+
{
29+
return HasID(feature)
30+
? feature.Attributes[IdAttributeName]
31+
: null;
32+
}
33+
34+
/// <summary>
35+
/// Function to evaluate if a feature has an ID
36+
/// </summary>
37+
/// <param name="feature">The feature</param>
38+
/// <returns><value>true</value> if <paramref name="feature"/> has an identifier assigned, otherwise <value>false</value></returns>
39+
/// <exception cref="ArgumentNullException">Thrown, if <paramref name="feature"/> is <valu>null</valu></exception>
40+
public static bool HasID(this IFeature feature)
41+
{
42+
if (feature == null)
43+
throw new ArgumentNullException("feature");
44+
45+
return feature.Attributes.Exists(IdAttributeName);
46+
}
47+
}
48+
}

NetTopologySuite/Features/IFeature.cs

+9
Original file line numberDiff line numberDiff line change
@@ -2,10 +2,19 @@
22

33
namespace NetTopologySuite.Features
44
{
5+
/// <summary>
6+
/// Interface for feature classes
7+
/// </summary>
58
public interface IFeature
69
{
10+
/// <summary>
11+
/// Gets or sets the attributes for the feature
12+
/// </summary>
713
IAttributesTable Attributes { get; set; }
814

15+
/// <summary>
16+
/// Gets or sets the feature's geometry
17+
/// </summary>
918
IGeometry Geometry { get; set; }
1019
}
1120
}

NetTopologySuite/NetTopologySuite.csproj

+1
Original file line numberDiff line numberDiff line change
@@ -146,6 +146,7 @@
146146
<Compile Include="EdgeGraph\HalfEdge.cs" />
147147
<Compile Include="EdgeGraph\MarkHalfEdge.cs" />
148148
<Compile Include="Features\FeatureCollection.cs" />
149+
<Compile Include="Features\FeatureExtensions.cs" />
149150
<Compile Include="Features\IFeature.cs" />
150151
<Compile Include="Geometries\Geometry.cs" />
151152
<Compile Include="Geometries\GeometryComponentFilter.cs" />

PortableClassLibrary/NetTopologySuite.Pcl/NetTopologySuite.Pcl.csproj

+3
Original file line numberDiff line numberDiff line change
@@ -85,6 +85,9 @@
8585
<Compile Include="..\..\NetTopologySuite\Features\FeatureCollection.cs">
8686
<Link>Features\FeatureCollection.cs</Link>
8787
</Compile>
88+
<Compile Include="..\..\NetTopologySuite\Features\FeatureExtensions.cs">
89+
<Link>Features\FeatureExtensions.cs</Link>
90+
</Compile>
8891
<Compile Include="..\..\NetTopologySuite\Features\IFeature.cs">
8992
<Link>Features\IFeature.cs</Link>
9093
</Compile>

0 commit comments

Comments
 (0)