Hi all,
I think GIS for Web Developers is a great book … up until chapter 8. Chapters 8 & 9 are riddled with errors (especially chapter 9!) I came to these forums hoping to get some answers however support for the book seems to be lax.
Here are a couple issues I had:
1. Chapter 8, pg. 269. In the last paragraph, the author instructs us to visit geoserver/webapps/geoserver/preview to view default map files for preview maps. However, my directory was empty. I think this is because the latest version of geoserver uses OpenLayers (discussed in section 8.2) instead of Mapbuilder. Since OpenLayers supports tiled maps, geoserver doesn’t need to preload the maps on startup hence the directory is empty (this is my best guess anyway).
2. Chapter 9, pg. 211. The author uses groovy scripting language to create a sql script to import comma delimited data into postgis. The script building is clear up until pg. 211. There are missing methods, and methods that don’t appear to be supported by groovy (for example, I am using the windows version and noQuote() is not supported). I am not an experienced groovy user however I created a script that works (at least for me). I was able to create the script file, load the data into the database and use the database to view it in Google Earth and NASA World Wind. I have included my version of the script (as it should work with geocoder.us on pg. 214) at the end of the post for anyone who needs help. Please note that I didn’t include the code for Yahoo (pg. 215).
Overall the book is well written, and I love the tutorial style the author uses. My issue was with the editing at the end of the book. I understand that open source applications change so I can forgive issue (1). However, the script in chapter 9 should have worked. There are too many missing pieces. The author needs to secure a more thorough and detail oriented editor for the next edition of the book.
Thanks and have a great day! Charity
Remember to change the paths to point to your input and output files!
// Script state for querying geocoder on page 214 of GIS for Web Developers (Chapter 9)
public class GetNext
{
public String[] getNext(String self, int numberOf)
{
def list = [];
def st = new StringTokenizer(self, ",")
numberOf.times
{
def thisToken = st.nextToken()
while(thisToken.startsWith("\"") && !thisToken.endsWith("\"") )
{
thisToken += "," + st.nextToken()
}
list << thisToken
}
return list
} // End getNext
}
public class Addr
{
String id
String name
String address
String city
String state
String zip
String lat
String lon
String epsg
String addressNormalized
String cityNormalized
String stateNormalized
String zipNormalized
def theGeom = "null"
def matcher
public Addr(String[] tokens)
{
// Strip out all quotes
matcher = (tokens[0] =~ /"/)
id = matcher.replaceAll("")
matcher = (tokens[1] =~ /"/)
name = matcher.replaceAll("")
matcher = (tokens[2] =~ /"/)
address = matcher.replaceAll("")
matcher = (tokens[3] =~ /"/)
city = matcher.replaceAll("")
matcher = (tokens[4] =~ /"/)
state = matcher.replaceAll("")
matcher = (tokens[5] =~ /"/)
zip = matcher.replaceAll("")
}
public boolean geoCode()
{
def urlStart = "http://rpc.geocoder.us/service/csv?address="
def urlBody = "${address},${city},${state},${zip}"
def urlEncoded = urlStart + URLEncoder.encode(urlBody, "UTF-8")
new URL(urlEncoded).eachLine{ line->
println "\t$line}"
if(line.startsWith("2"))
{
addressNormalized = "NOT FOUND"
}
else
{
def getNextObj = new GetNext()
def tokens = getNextObj.getNext(line,6)
lat = tokens[0]
lon = tokens[1]
addressNormalized = tokens[2].fixQuote()
cityNormalized = tokens[3].fixQuote()
stateNormalized = tokens[4].fixQuote()
zipNormalized = tokens[5].fixQuote()
theGeom = "GeomFromText('POINT(${lon} ${lat})', 4326)"
}
}
return addressNormalized != "NOT FOUND"
}
// This method is missing from example
public String toSql(String inString)
{
return inString + "${theGeom}," + "'${addressNormalized}'," +
"'${cityNormalized}'," + "'${stateNormalized}'," + "'${zipNormalized}'"
}
} // End class Addr
class Fixer
{
static String fixQuote(String self)
{
self = self[0] + self[1..-2].replaceAll("\'", "\'\'") + self[-1]
if(self.startsWith("\""))
{
return "'" + self[1..-2] + "'"
}
else
{
return self
}
}
} // End class Fixer
// On your mark, get set, go!
def outputFile = new File("college.sql")
if(outputFile.exists()){ outputFile.delete() }
def ddl = """
BEGIN;
CREATE TABLE college (
"id" numeric PRIMARY KEY,
"name" varchar(255),
"address" varchar(255),
"city" varchar(255),
"state" varchar(255),
"zip" varchar(255),
"address_n" varchar(255),
"city_n" varchar(255),
"state_n" varchar(255),
"zip_n" varchar(255)
);
SELECT
AddGeometryColumn('college','location',4326,'POINT',2);
"""
outputFile.append(ddl)
def insertStart = """insert into college("id", "name", "address",
"city", "state", "zip", "location",
"address_n", "city_n", "state_n", "zip_n") values ("""
def insertEnd = ");"
def counter = 0
def found = 0
def notFound = 0
def inputFile = new File("..//CollegesandUniversities//sample2.csv") //USER DEFINED
use(Fixer)
{
inputFile.eachLine{ line ->
def getNextObj = new GetNext()
def String[] tokens = getNextObj.getNext(line, 6)
if(counter == 0)
{
counter++;
}
else
{
println "${counter++} ${tokens[1].fixQuote()}" // show what is going on
def addr = new Addr(tokens)
if(addr.geoCode())
{
found++
insertMiddle = ""
for(i in 0..5)
{
insertMiddle += "${tokens[i].fixQuote()},"
}
println insertMiddle
insertMiddle = addr.toSql(insertMiddle)
println insertMiddle
//insertMiddle = insertMiddle[0..-2] // strip off trailing comma
outputFile.append("${insertStart}${insertMiddle}${insertEnd}\n")
}
else
{
notFound++
}
} // end if counter == 0
// Write out current status
statusFile = new File("status.txt")
statusFile.append("Total: ${counter} Found: ${found} Unfound:${notFound}\n")
} // End eachLine
} // end use(Fixer)
outputFile.append("END;")