[In English]
gvSIG 2.0 y posteriores permiten crear una capa directamente desde una tabla de una base de datos PostgreSQL/PostGIS, incluso añadiéndoles una restricción SQL, es decir, con una claúsula WHERE sobre la tabla, de manera que uses únicamente las columnas que te interesen.
Sin embargo, yo necesitaba crear una capa a partir de una tabla incluyendo, en la restricción SQL, un FROM que me permitiera combinar diferentes tablas de mi BD. Para ello he utilizado la opción de scripting con Jython que ofrece gvSIG (en mi caso, en la versión 2.1).
[NOTA: gvSIG 1.12 también tiene un módulo de scripting, pero a) es menos potente, y b) no ha sido capaz de cargar el script que he escrito, la consola de Jython me indica que “no module named gvsig”]
El primer paso para poder trabajar con los scripts Jython es instalar el módulo de scripting en gvSIG, si no está instalado por defecto. A partir de ahí, ya se pueden crear y lanzar los scripts Jython que queramos desarrollar. No es el objetivo de esta entrada explicar con detalle la instalación y el manejo del entorno de scripting; para ello, consultar la documentación de scripting de gvSIG, las entradas de scripting del blog de gvSIG, o esta entrada del blog másquesig. Como veréis, crear nuestros propios scripts abre muchísimas posibilidades a la hora de trabajar con gvSIG.
Para acceder a BDs en Jython se puede usar el paquete zxJDBC, que es un estándar desde la versión 2.1 de Jython; aquí se puede encontrar mucha información sobre el mismo, pero resumiendo:
- Es útil para scripts aislados y sin necesidad de portabilidad.
- Comunica dos estándares: JDBC, el estándar de acceso a bases de datos de Java, y DBI, el estándar de acceso a bases de datos de Python.
Sin embargo, no he conseguido hacer que funcionara. Posiblemente el problema es el que se comenta y soluciona aquí, relativo al classpath; sin embargo, sospecho que como la herramienta de scripting está “dentro” de gvSIG, la solución que proponen no funciona. Tampoco funciona esta variante que he encontrado.
Así que la solución ha sido trabajar directamente en Java. Lo primero ha sido descargar el driver JDBC para PostgreSQL de aquí; he escogido el JDBC 4 para PostgreSQL 9.1 y me ha ido bien.
Para lograr acceder a la BD y ejecutar sentencias SQL me he basado en la información encontrada en este enlace, este enlace, y este otro. El driver lo guardo en el directorio donde he instalado el gvSIG (no en el directorio que crea gvSIG), y en el script primero accedo a él, y luego lo cargo. Una vez tengo acceso a la BD, puedo ejecutar la sentencia SQL que desee, con lo que la potencia de las búsquedas es mucho mayor. La única condición es que esa búsqueda devuelva las coordenadas X e Y de los puntos que queremos insertar en la capa.
Este es el código básico que resuelve el acceso a la BD, la ejecución de la sentencia, y la creación de la nueva capa con los datos devueltos por la misma.
[En español]
gvSIG 2.0 and later allow to create a layer from a table in a PostgreSQL/PostGIS database, even adding a SQL constraint, that is, a WHERE clause on the table, so you can recover only the columns you need.
However, I wanted to create a layer from a table including, in the SQL constraint, also a FROM clause which allowed me to combine different tables in my DB. So I have used the scripting possibilities that, via Jython, offers gvSIG (in my case, I am working with gvSIG 2.1)
[NOTE: gvSIG 1.12 has a scripting module too, but a) it is not as powerful, and b) it could not load the script I have written, and the Jython console shows the message “no module named gvsig”]
The first step in order to write Jython scripts in gvSIG is to install the scripting module (if it is not installed by default). From there on, you can create and launch your own Jython scripts. It is out of the scope of this post to explain in detail the installation process and how to work with the scripting module; the interested reader may consult the gvSIG scripting documentation, the gvSIG blog’s posts about scripting, or this post on blog másquesig. As you can see, creating our own scripts offers a lot of possibilities when we work with gvSIG.
For accessing databases using Jython you can use the zxJDBC package, which is a standard since version 2.1 of Jython; you can find here much more information about it, though, to cut a long story short (I love that song by Spandau Ballet 🙂 !!):
- It is useful for scripts that work in an isolated manner and do not have to assure portability.
- It is a link between two standards: JDBC, the Java standard for accessing databases, and DBI, the Python standard for the same task.
However, I couldn’t make it work. I would say that the problem is the one commented and solved here, due to classpath issues; however, I guess that, since the scripting module is “inside” gvSIG, the proposed solution does not work, neither does this variation I have found.
So I have used Java. First, you have to download the JDBC driver for PostgreSQL from here; I have chosen JDBC 4 for PostgreSQL 9.1 and it works fine.
In order to connect to the DB and then execute SQL sentences, I have used the information I found in this link, this link, and this other link. I stored the driver in the directory where I have installed gvSIG (not in the directory created by gvSIG), then the script appends that path, and finally the driver is uploaded. Any SQL sentence can be executed, so the searches in the BD are much more flexible. The only restriction that must be taken into account is that the search returns the X and Y coordinates of the points we want to insert into the new layer. This is the basic code that access to the DB, executes the query, and creates a new layer with the returned data.
import sys
import os
from gvsig import *
from geom import *
from java.util import Properties
sys.path.append(“/home/anita/gvSIG-desktop/gvSIG-desktop-2.1.0/postgresql-9.1-903.jdbc4.jar”);
import org.postgresql.Driver as Driver
def main():
# Create the new layer
projection = currentView().getProjection()
newLayerSchema = createSchema()
newLayerSchema.append(“ID”,”INTEGER”)
newLayerSchema.append(“GEOMETRY”,”GEOMETRY”)
newLayerName = “/home/anita/YOUR_PATH”
newLayer = createShape(newLayerSchema,newLayerName,CRS=projection,geometryType=POINT)
# Connect to the database
props = Properties()
props.put(“user”,YOUR_USER)
props.put(“password”,YOUR_PASSWORD)
db = Driver().connect(“jdbc:postgresql://localhost/YOUR_DB“, props)
# Get geometry info from database and insert it into the new layer
c = db.createStatement()
rs = c.executeQuery(“select table.id, ST_X(table.coordinatesxy),ST_Y(table.coordenatesxy) from YOUR_TABLES where YOUR_WHERE_CLAUSE“)
data = {}
while rs.next():
id = rs.getInt(1)
newX = rs.getObject(2)
newY = rs.getObject(3)
print(id,newX,newY)
newGeom = createPoint(newX,newY)
dbValues = {“ID”:id,”GEOMETRY”:newGeom}
newLayer.append(dbValues)
rs.close()
c.close()
db.close()
currentView().addLayer(newLayer)
newLayer.commit()