I want to extract some data from a shapefile,
I have this function that can read a shapefile file is show on a map
i can read some informations but i m lost with extract many info in this file
public class Quickstart {
public static void main(String[] args) throws Exception {
// display a data store file chooser dialog for shapefiles
File file = JFileDataStoreChooser.showOpenFile("shp", null);
if (file == null) {
return;
}
FileDataStore dataStore = FileDataStoreFinder.getDataStore(file);
//SimpleFeatureSource featureSource = dataStore.getFeatureSource();
String t = dataStore.getTypeNames()[0];
SimpleFeatureSource featureSource = dataStore.getFeatureSource(t);
SimpleFeatureType schema = featureSource.getSchema();
//String geomType = schema.getGeometryDescriptor().getType().getBinding().getName();
GeometryDescriptor geom = schema.getGeometryDescriptor();
List<AttributeDescriptor> attributes = schema.getAttributeDescriptors();
GeometryType geomType = null;
List<AttributeDescriptor> attribs = new ArrayList<AttributeDescriptor>();
for (AttributeDescriptor attrib : attributes) {
AttributeType type = attrib.getType();
if (type instanceof GeometryType) {
geomType = (GeometryType) type;
} else {
attribs.add(attrib);
}
}
GeometryTypeImpl gt = new GeometryTypeImpl(
new NameImpl("the_geom"), geomType.getBinding(),
geomType.getCoordinateReferenceSystem(),
geomType.isIdentified(), geomType.isAbstract(),
geomType.getRestrictions(), geomType.getSuper(),
geomType.getDescription());
GeometryDescriptor geomDesc = new GeometryDescriptorImpl(
gt, new NameImpl("the_geom"),
geom.getMinOccurs(), geom.getMaxOccurs(),
geom.isNillable(), geom.getDefaultValue());
attribs.add(0, geomDesc);
SimpleFeatureType shpType = new SimpleFeatureTypeImpl(
schema.getName(), attribs, geomDesc,
schema.isAbstract(), schema.getRestrictions(),
schema.getSuper(), schema.getDescription());
dataStore.createSchema(shpType);
CachingFeatureSource cache = new CachingFeatureSource(featureSource);
// Create a map context and add our shapefile to it
MapContext map = new DefaultMapContext();
map.setTitle("Using cached features");
map.addLayer(cache, null);
// Now display the map
JMapFrame.showMap(map);
}
i want to extract this information :
POLYGON((0.6883 49.4666,0.6836 49.4664,0.6836 49.4663,0.6841 49.466,0.6844 49.4658,0.6847 49.4653,0.685 49.465,
0.6852 49.4646,0.6865 49.4624,0.6868 49.4621,0.6869 49.4618,0.6873 49.4617,0.6874 49.4617,0.6878 49.4616,0.6884 49.4615,
0.6898 49.4614,0.6909 49.4613,0.6909 49.4618,0.6913 49.4618,0.6906 49.4667,0.6883 49.4666))
I do not know how to do
plz help
It is hard to see how that snippet is giving you any attributes back.
If you want the geometry of a feature then you need to use
Geometry geom = feature.getDefaultGeometry();
to write it out as Well Known Text (WKT) you can use the .toString() method or use a WKTWriter to give you greater control over the formatting.
Related
I want to export the results of an SQL query, fired through JDBC, to a file; and then import that result, at some point later.
I'm currently doing it by querying the database through a NamedParameterJdbcTemplate of Spring which returns a SqlRowSet that I can iterate. In each iteration, I extract desired fields and dump the result into a CSV file, using PrintWriter.
final SqlRowSet rs = namedJdbcTemplate.queryForRowSet(sql,params);
while (rs.next()) {
The problem is that when I read back the file, they are all Strings and I need to cast them to their proper types, e.g Integer, String, Date etc.
while (line != null) {
String[] csvLine = line.split(";");
Object[] params = new Object[14];
params[0] = csvLine[0];
params[1] = csvLine[1];
params[2] = Integer.parseInt(csvLine[2]);
params[3] = csvLine[3];
params[4] = csvLine[4];
params[5] = Integer.parseInt(csvLine[5]);
params[6] = Integer.parseInt(csvLine[6]);
params[7] = Long.parseLong(csvLine[7]);
params[8] = formatter.parse(csvLine[8]);
params[9] = Integer.parseInt(csvLine[9]);
params[10] = Double.parseDouble(csvLine[10]);
params[11] = Double.parseDouble(csvLine[11]);
params[12] = Double.parseDouble(csvLine[12]);
params[13] = Double.parseDouble(csvLine[13]);
batchParams.add(params);
line = reader.readLine();
}
Is there a better way to export this SqlRowSet to a file in order to facilitate the import process later on; some way to store the schema for an easier insertion into the DB?
If parsing is your concern, one way of handling this is,
Create a parser Factory interface, say ParserFactory
Create a parse interface, say MyParser
Have MyParser implemented using Factory Method Pattern, i.e. IntegerParser implements MyParser etc.
Have your factory class names as a header in your CSV
This way your calling code would look like,
List<String> headerRow = reader.readLine().split(";"); // Get the 1st row here
Map<String, MyParser> parsers = new HashMap<>();
for(int i = 0; i < headerRow.length(); i++) {
if(!parser.containsKey(headerRow[i]))
parsers.put(headerRow[i], ParserFactory.get(headerRow[i]));
}
line = reader.readLine();
while (line != null) { // From 2nd row onwards
String[] row = line.split(";");
Object[] params = new Object[row.length()];
for(int i = 0; i<row.length(); i++) {
params[i] = parser.get(headerRow[i]).parse(row[i]);
}
batchParams.add(params);
line = reader.readLine();
}
You might like to extract out the creation of parser map, into it's own method. Or let your ParserFactory take headerRow as parameter, and return respective parsers as a result. Something like,
List<String> headerRow = reader.readLine().split(";"); // Get the 1st row here
Map<String, MyParser> parsers = ParserFactory.getParsers(headerRow);
I am transforming a shapefile by adding a new column attributes. Since this task is performed using Java, the only option I know for now is using Geotools. I have 2 main concerns:
1. I am not able to figure out how do I actually add a new column variable. Is the feature.setAttribute("col","value") the answer?
I see from this post just the example:https://gis.stackexchange.com/questions/215660/modifying-feature-attributes-of-a-shapefile-in-geotools but I dont get the solution.
//Upload the ShapeFile
File file = JFileDataStoreChooser.showOpenFile("shp", null);
Map<String, Object> params = new HashMap<>();
params.put("url", file.toURI().toURL());
DataStore store = DataStoreFinder.getDataStore(params);
SimpleFeatureSource featureSource = store.getFeatureSource(store.getTypeNames()[0]);
String typeName = store.getTypeNames()[0];
FeatureSource<SimpleFeatureType, SimpleFeature> source =
store.getFeatureSource(typeName);
Filter filter = Filter.INCLUDE;
FeatureCollection<SimpleFeatureType, SimpleFeature> collection = source.getFeatures(filter);
try (FeatureIterator<SimpleFeature> features = collection.features()) {
while (features.hasNext()) {
SimpleFeature feature = features.next();
//adding new columns
feature.setAttribute("ShapeID", "SHP1213");
feature.setAttribute("UserName", "John");
System.out.print(feature.getID());
System.out.print(":");
System.out.println(feature.getDefaultGeometryProperty().getValue());
}
}
/*
* Write the features to the shapefile
*/
Transaction transaction = new DefaultTransaction("create");
// featureSource.addFeatureListener(fl);
if (featureSource instanceof SimpleFeatureStore) {
SimpleFeatureStore featureStore = (SimpleFeatureStore) featureSource;
featureStore.setTransaction(transaction);
try {
featureStore.addFeatures(collection);
transaction.commit();
} catch (Exception problem) {
problem.printStackTrace();
transaction.rollback();
} finally {
transaction.close();
}
System.exit(0); // success!
} else {
System.out.println(typeName + " does not support read/write access");
System.exit(1);
}
Assuming that setattribute is the one which adds, I get the following error for the above code.
Exception in thread "main" org.geotools.feature.IllegalAttributeException:Unknown attribute ShapeID:null value:null
at org.geotools.feature.simple.SimpleFeatureImpl.setAttribute(SimpleFeatureImpl.java:238)
at org.geotools.Testing.WritetoDatabase.main(WritetoDatabase.java:73)
2. After modifying these changes I want to store it in the database(PostGIS). I figured out the below snippet does the task, but doesn't seems to work for me with just shape file insertion
Properties params = new Properties();
params.put("user", "postgres");
params.put("passwd", "postgres");
params.put("port", "5432");
params.put("host", "127.0.0.1");
params.put("database", "test");
params.put("dbtype", "postgis");
dataStore = DataStoreFinder.getDataStore(params);
The error is a NullPointerException in the above case.
In GeoTools a (Simple)FeatureType is immutable (unchangeable) so you can't just add a new attribute to a shapefile. So first you must make a new FeatureType with your new attribute included.
FileDataStore ds = FileDataStoreFinder.getDataStore(new File("/home/ian/Data/states/states.shp"));
SimpleFeatureType schema = ds.getSchema();
// create new schema
SimpleFeatureTypeBuilder builder = new SimpleFeatureTypeBuilder();
builder.setName(schema.getName());
builder.setSuperType((SimpleFeatureType) schema.getSuper());
builder.addAll(schema.getAttributeDescriptors());
// add new attribute(s)
builder.add("shapeID", String.class);
// build new schema
SimpleFeatureType nSchema = builder.buildFeatureType();
Then you need to convert all your existing features to the new schema and add the new attribute.
// loop through features adding new attribute
List<SimpleFeature> features = new ArrayList<>();
try (SimpleFeatureIterator itr = ds.getFeatureSource().getFeatures().features()) {
while (itr.hasNext()) {
SimpleFeature f = itr.next();
SimpleFeature f2 = DataUtilities.reType(nSchema, f);
f2.setAttribute("shapeID", "newAttrValue");
//System.out.println(f2);
features.add(f2);
}
}
Finally, open the Postgis datastore and write the new features to it.
Properties params = new Properties();
params.put("user", "postgres");
params.put("passwd", "postgres");
params.put("port", "5432");
params.put("host", "127.0.0.1");
params.put("database", "test");
params.put("dbtype", "postgis");
DataStore dataStore = DataStoreFinder.getDataStore(params);
SimpleFeatureSource source = dataStore.getFeatureSource("tablename");
if (source instanceof SimpleFeatureStore) {
SimpleFeatureStore store = (SimpleFeatureStore) source;
store.addFeatures(DataUtilities.collection(features));
} else {
System.err.println("Unable to write to database");
}
I'm using Milo and its example server and client. I'm adding nodes to the server but I can't figure out how to add EuInformation, i.e., unit and description. I thought about using the ExtensionObject but since EuInformation does not implement Serializable I don't know how to pass it to the ExtensionObject. I'd also like to know how I can get the namespace ID and URI on client side. So far I just set them statically as I have access to the classes.
I've implemeted the AddNodes on server side. I can add nodes, read nodes and write to nodes.
Here's what I'm doing on client side:
// Should somehow get the namespace ID and namespace dynamically.
// Maybe by iterating through all nodes??
ExpandedNodeId parentNodeId = new ExpandedNodeId(
new nodeId(2,DatatypeNamespace.NODE_IDENTIFIER),
datatypeNamespace.NAMESPACE_URI, 0);
NodeId referenceTypeId = Identifiers.String;
// Define the new node.
ExpandedNodeId requestedNewNodeId = new ExpandedNodeId(new NodeId(2, "NewNode"),
DatatypeNamespace.NAMESPACE_URI, 0);
QualifiedName browseName = new QualifiedName(2, "NewNode");
// How to get this to the server??
EUInformation euinfo = new EUInformation(null,-1,LocalizedText.english("MyUnit"),
LocalizedText.english("My Description"));
ExpandedNodeId typeDef = new ExpandedNodeId(Identifiers.BaseVariableType,
DatatypeNamespace.NAMESPACE_URI, 0);
AddNodesItem newItem = new AddNodesItem(parentNodeId, referenceTypeId,
requestedNewNodeId,rowseName,NodeClass.VariableType, null, typeDef);
List<AddNodesItem> items = new ArrayList<AddNodesItem>();
items.add(newItem);
client.addNodes(items).get();
EDIT
With the help of Kevin Herron's answer I worked something out: I adjusted the write() in my namespace class. I can now modify the display name and description of the node with the values of the EUInformation. Here's my write() method:
#Override
public void write(WriteContext context, List<WriteValue> writeValues) {
List<StatusCode> results = Lists.newArrayListWithCapacity(writeValues.size());
for (WriteValue writeValue : writeValues) {
ServerNode node = server.getNodeMap().get(writeValue.getNodeId());
if (node != null) {
// Get the type of the variant thats about to be written to the node
NodeId variantType = writeValue.getValue().getValue().getDataType().get();
if (variantType.equals(Identifiers.Structure)) {
ExtensionObject o = (ExtensionObject) writeValue.getValue().getValue().getValue();
if (o.getEncodingTypeId().equals(Identifiers.EUInformation_Encoding_DefaultBinary)) {
EUInformation euInformation = (EUInformation) o.decode();
node.setDescription(euInformation.getDescription());
node.setDisplayName(euInformation.getDisplayName());
System.out.println("Wrote EUInformation " + euInformation);
results.add(StatusCode.GOOD);
context.complete(results);
return;
}
}
try {
node.writeAttribute(new AttributeContext(context), writeValue.getAttributeId(),
writeValue.getValue(), writeValue.getIndexRange());
results.add(StatusCode.GOOD);
System.out.println(String.format("Wrote value %s to %s attribute of %s",
writeValue.getValue().getValue(),
AttributeId.from(writeValue.getAttributeId()).map(Object::toString).orElse("unknown"),
node.getNodeId()));
} catch (UaException e) {
System.out.println(String.format("Unable to write %s", writeValue.getValue()));
results.add(e.getStatusCode());
}
} else {
results.add(new StatusCode(StatusCodes.Bad_NodeIdUnknown));
}
}
context.complete(results);
}
Ok, so you would add a new VaribleNode with a TypeDefinition of Property (Identifiers.PropertyType).
Then you would write to its Value attribute so it contains the EUInformation object:
EUInformation euInformation = ...
Variant v = new Variant(ExtensionObject.encode(euInformation));
...write the value to the node you created...
I want to modify an existing *.rptdesign file and save it under a new name.
The existing file contains a Data Set with a template SQL select statement and several DS parameters.
I'd like to use an actual SQL select statement which uses only part of the DS parameters.
However, the following code results in the exception:
Exception in thread "main" `java.lang.RuntimeException`: *The structure is floating, and its handle is invalid!*
at org.eclipse.birt.report.model.api.StructureHandle.getStringProperty(StructureHandle.java:207)
at org.eclipse.birt.report.model.api.DataSetParameterHandle.getName(DataSetParameterHandle.java:143)
at org.eclipse.birt.report.model.api.DataSetHandle$DataSetParametersPropertyHandle.removeParamBindingsFor(DataSetHandle.java:851)
at org.eclipse.birt.report.model.api.DataSetHandle$DataSetParametersPropertyHandle.removeItems(DataSetHandle.java:694)
--
OdaDataSetHandle dsMaster = (OdaDataSetHandle) report.findDataSet("Master");
HashSet<String> bindVarsUsed = new HashSet<String>();
...
// find out which DS parameters are actually used
HashSet<String> bindVarsUsed = new HashSet<String>();
...
ArrayList<OdaDataSetParameterHandle> toRemove = new ArrayList<OdaDataSetParameterHandle>();
for (Iterator iter = dsMaster.parametersIterator(); iter.hasNext(); ) {
OdaDataSetParameterHandle dsPara = (OdaDataSetParameterHandle)iter.next();
String name = dsPara.getName();
if (name.startsWith("param_")) {
String bindVarName = name.substring(6);
if (!bindVarsUsed.contains(bindVarName)) {
toRemove.add(dsPara);
}
}
}
PropertyHandle paramsHandle = dsMaster.getPropertyHandle( OdaDataSetHandle.PARAMETERS_PROP );
paramsHandle.removeItems(toRemove);
What is wrong here?
Has anyone used the DE API to remove parameters from an existing Data Set?
I had similar issue. Resolved it by calling 'removeItem' multiple times and also had to re-evaluate parametersIterator everytime.
protected void updateDataSetParameters(OdaDataSetHandle dataSetHandle) throws SemanticException {
int countMatches = StringUtils.countMatches(dataSetHandle.getQueryText(), "?");
int paramIndex = 0;
do {
paramIndex = 0;
PropertyHandle odaDataSetParameterProp = dataSetHandle.getPropertyHandle(OdaDataSetHandle.PARAMETERS_PROP);
Iterator parametersIterator = dataSetHandle.parametersIterator();
while(parametersIterator.hasNext()) {
Object next = parametersIterator.next();
paramIndex++;
if(paramIndex > countMatches) {
odaDataSetParameterProp.removeItem(next);
break;
}
}
if(paramIndex < countMatches) {
paramIndex++;
OdaDataSetParameter dataSetParameter = createDataSetParameter(paramIndex);
odaDataSetParameterProp.addItem(dataSetParameter);
}
} while(countMatches != paramIndex);
}
private OdaDataSetParameter createDataSetParameter(int paramIndex) {
OdaDataSetParameter dataSetParameter = StructureFactory.createOdaDataSetParameter();
dataSetParameter.setName("param_" + paramIndex);
dataSetParameter.setDataType(DesignChoiceConstants.PARAM_TYPE_INTEGER);
dataSetParameter.setNativeDataType(1);
dataSetParameter.setPosition(paramIndex);
dataSetParameter.setIsInput(true);
dataSetParameter.setIsOutput(false);
dataSetParameter.setExpressionProperty("defaultValue", new Expression("<evaluation script>", ExpressionType.JAVASCRIPT));
return dataSetParameter;
}
I'm literally struggling with this new API and the lack of examples for core things like the NRT Manager.
I followed this example and here is the final result:
This is how the NRT Manager is built:
analyzer = new StopAnalyzer(Version.LUCENE_40);
config = new IndexWriterConfig(Version.LUCENE_40, analyzer);
writer = new IndexWriter(FSDirectory.open(new File(ConfigUtil.getProperty("lucene.directory"))), config);
mgrWriter = new NRTManager.TrackingIndexWriter(writer);
ReferenceManager<IndexSearcher> mgr = new NRTManager(mgrWriter, new SearcherFactory(), true);
Adding a new element to the NRT Manager's writer:
long gen = -1;
try{
Document userDoc = DocumentManager.getDocument(user);
gen = mgrWriter.addDocument(userDoc);
} catch (Exception e) {}
return gen;
After some small amount of time I need to update the previous document:
// Acquire a searcher from the NRTManager. I am using the generation obtained in the creation step
((NRTManager)mgr).waitForGeneration(gen);
searcher = mgr.acquire();
//Search for the document based on some user id
Term idTerm = new Term(USER_ID, Integer.toString(userId));
Query idTermQuery = new TermQuery(term);
TopDocs result = searcher.search(idTermQuery, 1);
if (result.totalHits > 0) resultDoc = searcher.doc(result.scoreDocs[0].doc);
else resultDoc = null;
The problem is that resultDoc will always be null. What am I missing? I should not use commit() or flush() in orther to see those changes.
I am using a NRTManagerReopenThread as exemplified here.
LE userDoc creation
public static Document getDocument(User user) {
Document doc = new Document();
FieldType storedType = new FieldType();
storedType.setStored(true);
storedType.setIndexed(false);
// Store user data
doc.add(new Field(USER_ID, user.getId().toString(), storedType));
doc.add(new Field(USER_NAME, user.getFirstName() + user.getLastName(), storedType));
FieldType unstoredType = new FieldType();
unstoredType.setStored(false);
unstoredType.setIndexed(true);
Field field = null;
// Analyze Location
String tokens = "";
if (user.getLocation() != null && ! user.getLocation().isEmpty()){
for (Tag location : user.getLocation()) tokens += location.getName() + " ";
field = new Field(USER_LOCATION, tokens, unstoredType);
field.setBoost(Constants.LOCATION);
doc.add(field);
}
// Analyze Language
if (user.getLanguage() != null && ! user.getLanguage().isEmpty()){
// Same as Location
}
// Analyze Career
if (user.getCareer() != null && ! user.getCareer().isEmpty()){
// Same as Location
}
return doc;
}
Your problem is not NRT-related. You are searching agains the USER_ID field although it has not been indexed, this can't work. If you don't want your ID field to be tokenized, just call FieldType#setTokenized(false) (or just use StringField, which does exactly that by default: indexed by not tokenized).