DataUtilities¶
Working with GIS data can be difficult. Working with the number of classes in the GeoTools library can also be a bit intimidating. The DataUtilities a facade classes which can help simplify common data wrangling chores.
In almost all cases the methods for this class act as a front end for the classes provided by gt-main
. This documentation makes note of the classes used internally so you can learn how the library is put together and can go look for more control if needed.
If you do have any commonly used data hacks in your code; please submit a patch request to the issue tracker and we can add more useful methods here.
References:
DataUtilities (javadocs)
File¶
checkFileReadable(File, Logger)
checkDirectory(File)
excludeFilters(FilenameFilter, FilenameFilter...)
includeFilters(FilenameFilter, FilenameFilter...)
Allows
FilenameFilters
to be combined.
FeatureType¶
Working with FeatureType
can be a bit troubling, as much like Java String
it is immutable (cannot be modified once created).
FeatureType Creation¶
DataUtilities
provides the following methods to help you quickly create and modify FeatureType
information.
DataUtilities.createType( typeName, specification )
DataUtilities.createType( namespace, typeName, specification)
This is great for quickly whipping up a
FeatureType
when making test cases. For more control useSimpleFeatureTypeBuilder
as described ingt-api
.If to quickly describe some information:
SimpleFeatureType lineType = DataUtilities.createType("LINE", "centerline:LineString,name:\"\",id:0");
I admit that looks a bit strange, you can also use a Java class names if it makes you happy:
SimpleFeatureType schema = DataUtilities.createType("EDGE", "edge:Polygon,name:String,timestamp:java.util.Date");
If you need to set the coordinate reference system as well (with optional CRS authority, if not using
EPSG
):SimpleFeatureType lineType = DataUtilities.createType("LINE", "centerline:LineString:srid=32615,name:\"\",id:0"); SimpleFeatureType marsLineType = DataUtilities.createType("LINE", "marsPath:LineString:authority:IAU;srid=49900,name:\"\",id:0");
If you are into names spaces that can be handled as well:
SimpleFeatureType lineType = DataUtilities.createType("http://somewhere.net/","LINE", "centerline:LineString,name:\"\",id:0");
Now we don’t want to see you writing code to build up your initial “definition” String, that means you are doing something general (and dynamic!) and should go figure out
SimpleFeatureTypeBuilder
andSimpleFeatureBuilder
.DataUtilities.spec(SimpleFeatureType)
You can use this method to quickly get a text representation of a
FeatureType
:System.out.println("FeatureType: " + DataUtilities.spec(schema));
The representation is the same one used by
createType
above.
FeatureType Modify¶
Because a FeatureType
cannot be modified once created; all of the following methods
return a modified copy.
DataUtilities.createSubType(SimpleFeatureType, String[], CoordinateReferenceSystem)
DataUtilities.createSubType(SimpleFeatureType, String[], CoordinateReferenceSystem, String, URI)
DataUtilities.createSubType(SimpleFeatureType, String[])
Used to quickly produce a (slightly modified) copy of the provided
FeatureType
. Used to recast aFeatureType
with a desiredCoordinateReferenceSystem
or limit aFeatureType
to a specific list of attributes.There are actually a couple
subType
methods depending on how complicated you want to get.:FeatureType schema = DataUtilities.createType("EDGE", "edge:Polygon,name:String"); CoordinateReferenceSystem crs = CRS.decode( "EPSG:4326" ); schema = DataUtilities.createSubType( schema, null, crs );
You can also get a bit more complicated and choose exactly which attributes you want.:
FeatureType schema = DataUtilities.createType("EDGE", "edge:Polygon,name:String,timestamp:java.util.Date"); schema = DataUtilities.subType( schema, new String[]{"edge","name"}, null );
FeatureType Summary¶
FeatureType
forms an interesting little data structure as shown in the gt-api
diagrams.
The following methods traverse this data structure for you building up a summary to answer specific questions.
DataUtilities.addMandatoryProperties( schema, propertyNames )
Used to review a
FeatureType
and add the required properties to an existing list:List<PropertyName> requiredProperties = addMandatoryProperties( schema, null );
compare(schema1, schema2)
The
retype
methods allow us to start with an existingFeatureType
and produced a simplified or modified copy.This method compares two feature types to sort out if one is a simplification of the other.
value
compare
+1
if
schema1
is a sub type/reorder/re-namespace ofschema2
0
if
schema1
andschema2
are the same-1
if
schema1
andschema2
are not relatedcompareNames(schema1, schema2)
Similar tocompare(schema1, schema2)
but considers only schemas attribute descriptors during comparisonisMatch(AttributeDescriptor, AttributeDescriptor)
Used to check if values from the two attribute descriptors have a hope of matching. Both the name and the binding to a Java class are checked.
isMatch(AttributeDescriptor, AttributeDescriptor, boolean)
Used to check if values from the two attribute descriptors have a hope of matching. Boolean argument determines whether equality is determined by descriptor name only (false) or java class binding will also be considered (true) Internally used bycompareNames
Feature¶
These methods help you work with the values stored in an individual feature. They can quickly produce a set of default values, or parse a set of provided strings into the correct Java Objects as needed.
template(SimpleFeatureType)
template(SimpleFeatureType, String)
template(SimpleFeatureType, Object[])
template(SimpleFeatureType, String, Object[])
These template methods create a new Feature using of sensible default values in the event the user supplied null for a mandatory value.
defaultValues(SimpleFeatureType)
defaultValues(SimpleFeatureType, Object[])
defaultValue(AttributeDescriptor)
defaultValue(Class)
These methods provide sensible default values that are a good starting point for data entry (if you are giving your user a chance to enter new a new feature by hand).
parse(SimpleFeatureType, String, String[])
You can quickly parse out a new feature from input text:
SimpleFeature feature = DataUtilities.parse( schema, fid, text );
duplicate(Object)
Performs a deep copy of the provided attribute value. It is aware of JTS Geometry, and GeoTools constructs such as
SimpleFeature
and will take appropriate measures.attributesEqual(Object, Object)
You can safely compare if two attribute values are equal (without worrying about Geometry behaving funny):
DataUtilities.attributesEquals( feature1.getAttribute(1), feature2.getAttribute(1) );
reType(SimpleFeatureType, SimpleFeature)
reType(SimpleFeatureType, SimpleFeature, boolean)
These methods allow you to modify a feature to match a new schema:
void exampleRetype() throws Exception {
SimpleFeatureType origional =
DataUtilities.createType("LINE", "centerline:LineString,name:\"\",id:0");
SimpleFeatureType modified = DataUtilities.createSubType(origional, "centerline");
SimpleFeature feature = DataUtilities.template(origional);
SimpleFeature changed = DataUtilities.reType(modified, feature);
}
FeatureCollection¶
Creating Features has gotten a lot easier with the advent of SimpleFeatureTypeBuilder
.
You can still run into situations where adapting feature data is useful when calling methods. The DataUtilities
class can help by providing wrappers taking your feature information from Arrays
, Collections
, FeatureReaders
and other
In general we try and work with FeatureReader
and FeatureIterator
(as these support the
idea of “streaming” information larger than memory). You will find some areas of the code that want to load everything into memory (either as a Collection or Array) often for analysis.
FeatureCollection
FeatureCollection
is used a lot in GeoTools code giving you a chance to use the following methods.
DataUtilities.collection(FeatureCollection)
- copies into memory!DataUtilities.collection(FeatureReader)
- copies into memory!DataUtilities.collection( List<SimpleFeature> )
DataUtilities.collection( SimpleFeature )
DataUtilities.collection( SimpleFeature[] )
DataUtilities.collection( SimpleFeatureIterator )
DataUtilities
has helper methods to turn almost anything into a FeatureCollection
, this
is really helpful when working with an API that expects a FeatureCollection
.:
Feature[] array;
...
return DataUtilities.collection( array );
These methods are often used to add a single SimpleFeature
to a FeatureStore
:
featureStore.addFeatures( DataUtilities.collection( newFeature ) );
Do be careful some of these implementations suck everything into memory! With GIS data sizes this will eventually break your application.
results(SimpleFeature[])
results(SimpleFeatureCollection)
results(FeatureCollection<T, F>)
These methods convert to a FeatureCollection
; but with a twist. They will
produce an error (rather than an empty collection) if the input is null or empty.
In GeoTools 2.0 FeatureCollection
was called FeatureResults
, these methods are
left over from that time.
FeatureSource¶
FeatureSource
is a very capable class, in the worst case the wrappers provided here may need to load everything into memory to get the job done.
source(SimpleFeature[])
Will wrap a
FeatureSource
around the provided array allowing the features to be queried.source(FeatureCollection<SimpleFeatureType, SimpleFeature>)
In a similar fashion a
FeatureSource
is wrapped around the provided collection.There are optimized implementations for:
ListFeatureCollection
SpatialIndexFeatureCollection
TreeSetFeatureCollection
And as fall back of copying everything into a memory using a
CollectionDataStore
to hold the resulting feature source.createView(DataStore, Query)
Creates a light weight “view” that focuses on combining the provided query with any requests made to the resulting
featureSource
.dataStore( source )
Adapt source as a singleton
dataStore
FeatureReader¶
FeatureReader
is the best class we have to represent the nature of streaming large
quantities of information off disk and through your program.
The following methods allow you to simulate a FeatureReader
using information you
happen to have in memory.
DataUtilities.reader(Collection<SimpleFeature>)
DataUtilities.reader(FeatureCollection)
DataUtilities.reader(SimpleFeature[])
The FeatureReader
interface works in a similar manner to
Iterator<Feature>
with
the benefit of IOExceptions
in case you are streaming from disk.
DataUtilities
sill lets you adapt your own collection to this format.:
FeatureCollection collection;
return DataUtilities.reader( collection );
Summary¶
The following methods provide a summary of feature information; often gathering up boilerplate code that you would otherwise need to cut and paste into your application.
DataUtilities.list(FeatureCollection)
Loads the
FeatureCollection
into a normaljava.util.List
DataUtilities.fidSet(FeatureCollection<?, ?>)
Goes through the
FeatureCollection
and produced the set ofFeatureIds
as a simpleSet<String>
.These identifiers can be used to retrieve features individually.
An example use is displaying features in a table; by getting a set of identifiers you can uniquely identify each row, and then only query for the contents of the features displayed on screen as needed.
DataUtilities.bounds(FeatureCollection<? extends FeatureType, ? extends Feature>)
There are methods to quickly get the bounds from a
FeatureSource
orFeatureCollection
, but these methods are implementation dependent often making use of header information or summarizing the spatial index in order to get you an answer quickly.Use this method to go through each feature one by one and compute a bounds.
Cast¶
In GeoTools 2.7 we introduced the idea of a
SimpleFeatureCollection
(which is a short hand forFeatureCollection<SimpleFeatureType,SimpleFeature>
).
While this really helped with learning the library (and the amount of typing required to use it)
we needed to introduce the following methods to help people safely “cast” to a SimpleFeatureCollection
when they had a FeatureCollection
.
DataUtilities.simple(FeatureCollection<SimpleFeatureType, SimpleFeature>)
DataUtilities.simple(FeatureSource)
DataUtilities.simple(FeatureStore)
DataUtilities.simple(FeatureType)
DataUtilities.simple(FeatureLocking)
While the above methods do perform an instance of check; they are also willing to apply a wrapper to get the job done if needed.
In practice these methods are quick and easy to use:
SimpleFeatureCollection features = DataUtilities.simple(collection);
Query¶
A common task with gt-main
is preparing a Query
against a FeatureSource
. DataUtilities
has a number of methods to help.
DataUtilities.mixQueries(Query, Query, String)
Safely combines two queries in a sensible manner. The provided string is used for the name of the new query.
DataUtilities.simplifyFilter(Query)
Simplifies the filter contained in a query, eliminating non-functional clauses.
DataUtilities.resolvePropertyNames(Query, SimpleFeatureType)
DataUtilities.resolvePropertyNames(Filter, SimpleFeatureType)
These two methods rewrite full property names to simple attribute names. For example, property names such as
gml:name
are rewritten as simplyname
.DataUtilities.addMandatoryProperties(SimpleFeatureType, List<PropertyName>)
SortBy¶
DataUtilities.sortComparator(SortBy)
Creates a
Comparator
that can be used to sort features as indicated by theQuery
SortBy
provided.
Filter and Expression¶
Part of the fun of preparing a Query
is ensuring you ask for the correct values to
perform the task you have in mind.
We have a number of methods to list required attributes for a Filter
or Expression
:
DataUtilities.attributeNames( Filter )
DataUtilities.attributeNames( Filter, FeatureType )
DataUtilities.attributeNames( Expression )
DataUtilities.attributeNames( Expression, FeatureType )
The optional
FeatureType
is used as a reference point and can resolve any ambiguities between the simple XPath expressions, and the names used in theFeatureType
.Here is an example of using this information to request a
FeatureCollection
that has the required attributes to evaluate the provided expression for every feature.:String attributes[] = DataUtilities.attributeNames( expression ); Query query = new Query( typeName, Filter.ALL, attributes ); SimpleFeatureCollection results = featureSource.features( query );
DataUtilities.propertyNames( Filter )
DataUtilities.propertyNames( Filter, FeatureType )
DataUtilities.propertyNames( Expression )
DataUtilities.propertyNames( Expression, FeatureType )
A similar batch of methods using
FilterAttributeExtractor
to retrieve aSet<PropertyName>
.Using a
PropertyName
is slightly more useful when considering complex XPath expressions that use namespaces.
FilterAttributeExtractor
Internally the above methods use FilterAttributeExtractor
. You can use this class for
greater control.:
FilterAttributeExtractor extract = new FilterAttributeExtractor(null);
Set<String> names = new HashSet<String>();
// used to collect names from expression1, expression2, and filter
expression1.accept(extract, names);
expression2.accept(extract, names);
filter.accept(extract, names);
String array[] = extract.getAttributeNames();
Set<String> attributes = extract.getAttributeNameSet();
Set<PropertyName> properties = extract.getPropertyNameSet();