{"id":272,"date":"2007-08-03T13:54:02","date_gmt":"2007-08-03T17:54:02","guid":{"rendered":"http:\/\/blogs.law.harvard.edu\/jreyes\/2007\/08\/03\/geotools-wfs-t-update-request\/"},"modified":"2007-08-13T15:52:54","modified_gmt":"2007-08-13T19:52:54","slug":"geotools-wfs-t-update-request","status":"publish","type":"post","link":"https:\/\/archive.blogs.harvard.edu\/jreyes\/2007\/08\/03\/geotools-wfs-t-update-request\/","title":{"rendered":"Geotools, WFS-T Update Request"},"content":{"rendered":"<p>\nA pet project of mine has flung me into the exciting though less-than-firm territory of web-backed geographical information systems. Since I don&#8217;t have the thousands of dollars it costs to get a commercial server like those provided by ESRI, I&#8217;ve had to check out the open-source alternatives. And there are some out there. I&#8217;m using <a href=\"http:\/\/www.geoserver.org\">GeoServer<\/a>, and it works great! I can send all the web-feature service transactions (WFS-T) in XML I want and it works every time. Not bad if you want to make a <a href=\"http:\/\/www.maps.google.com\">GoogleMap<\/a> of your house on your own&#8212;so long as you&#8217;re content to hard-code everything by hand. Should you want to jazz things up a bit (i.e., make minimally useful dynamic maps), like me, then you have to do a little more work. Actually, you need to do a lot more work.\n<\/p>\n<p>\nGeoServer is built on top of a gargantuan set of Java libraries, collectively packaged under the name <a href=\"http:\/\/www.geotools.org\">GeoTools<\/a>. Now I appreciate that this thing exists, all two hundred and fifty megs of source code and all the functionality that comes with it. However, navigating the mountain of documentation for this thing is, at least for me, a little daunting. It took me a few days (and some serious help from my friend Matt) to figure out how to write a simple update transaction using their API. (Compare that to the forty-two seconds it takes me to type up the XML.)\n<\/p>\n<p>\nSince other people might want to know what they have to do update an attribute field using WFS with GeoTools, and since I couldn&#8217;t easily find out how to do it elsewhere, I&#8217;ve decided to post a short snippet of code right here on my blog. That&#8217;s right: my charity knows no bounds.\n<\/p>\n<p>\nIn this example I&#8217;m going to update the value of all the features (polygons, lines, points, whatever) that match a simple filter. Here I&#8217;m going to change the value of <var>propertyToUpdate<\/var> to <var>updatedValue<\/var> using a filter to get all the features with the attribute called <var>constraintProperty<\/var> with a value of <var>constraintValue<\/var>. I&#8217;ve marked them in red, so that it&#8217;s as easy as possible to customize this example to fit your needs. Let&#8217;s start with the XML that the <a href=\"http:\/\/www.opengeospatial.org\/standards\"> Open Geospatial Consortium<\/a> standards expects to see.\n<\/p>\n<blockquote><p>\n&lt;wfs:Transaction service=&#8221;WFS&#8221; version=&#8221;1.0.0&#8243;<br \/>\n&nbsp; &nbsp; &nbsp;xmlns:<font color=\"red\">myns<\/font>=&#8221;<font color=\"red\">http:\/\/www.domain.com\/ns<\/font>&#8221;<br \/>\n&nbsp; &nbsp; &nbsp;xmlns:ogc=&#8221;http:\/\/www.opengis.net\/ogc&#8221;<br \/>\n&nbsp; &nbsp; &nbsp;xmlns:wfs=&#8221;http:\/\/www.opengis.net\/wfs&#8221;&gt;<br \/>\n&nbsp; &lt;wfs:Update typeName=&#8221;<font color=\"red\">myns:LayerToUpdate<\/font>&#8220;&gt;<br \/>\n&nbsp; &nbsp; &lt;wfs:Property&gt;<br \/>\n&nbsp; &nbsp; &nbsp; &nbsp; &lt;wfs:Name&gt;<font color=\"red\">propertyToUpdate<\/font>&lt;\/wfs:Name&gt;<br \/>\n&nbsp; &nbsp; &nbsp; &nbsp; &lt;wfs:Value&gt;<font color=\"red\">updatedValue<\/font>&lt;\/wfs:Value&gt;<br \/>\n&nbsp; &nbsp; &lt;\/wfs:Property&gt;<br \/>\n&nbsp; &nbsp; &lt;ogc:Filter&gt;<br \/>\n&nbsp; &nbsp; &nbsp; &nbsp; &lt;ogc:PropertyIsEqualTo&gt;<br \/>\n&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &lt;ogc:PropertyName&gt;<font color=\"red\">constraintProperty<\/font>&lt;\/ogc:PropertyName&gt;<br \/>\n&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &lt;ogc:Literal&gt;<font color=\"red\">constraintValue<\/font>&lt;\/ogc:Literal&gt;<br \/>\n&nbsp; &nbsp; &nbsp; &nbsp; &lt;\/ogc:PropertyIsEqualTo&gt;<br \/>\n&nbsp; &nbsp; &lt;\/ogc:Filter&gt;<br \/>\n&nbsp;   &lt;\/wfs:Update&gt;<br \/>\n&lt;\/wfs:Transaction&gt;\n<\/p><\/blockquote>\n<p>\nNow let&#8217;s rock out the Java.\n<\/p>\n<p>\nLike I said, GeoTools is mammoth. To make life easy, we&#8217;re going to import a whole bunch of classes for this example. So many, in fact, that their number really warrants my displaying them here in their own list. What&#8217;s more, the names of some of classes (like Filter) show up in more than one package, and you need to keep track of which is used where. So keep an eye out for things from org.opengis.\n<\/p>\n<blockquote><p>\nimport java.io.IOException;<br \/>\nimport java.net.MalformedURLException;<br \/>\nimport java.net.URL;<br \/>\nimport java.util.HashMap;<br \/>\nimport java.util.Map;<br \/>\nimport java.util.logging.Level;<\/p>\n<p>import org.geotools.data.DataStore;<br \/>\nimport org.geotools.data.DefaultTransaction;<br \/>\nimport org.geotools.data.FeatureStore;<br \/>\nimport org.geotools.data.Transaction;<br \/>\nimport org.geotools.data.wfs.WFSDataStoreFactory;<br \/>\nimport org.geotools.feature.AttributeType;<br \/>\nimport org.geotools.feature.FeatureType;<br \/>\nimport org.geotools.filter.FilterFactoryFinder;<br \/>\nimport org.geotools.xml.XMLSAXHandler;<\/p>\n<p>import org.opengis.filter.Filter;<br \/>\nimport org.opengis.filter.FilterFactory;<br \/>\nimport org.opengis.filter.expression.Expression;\n<\/p><\/blockquote>\n<p>\nIn our constructor we&#8217;ll set up a connection to the WFS server using a URL.  If you&#8217;re tinkering with GeoServer, then that URL you&#8217;re looking for probably looks something like <var>http:\/\/localhost:8080\/geoserver\/wfs<\/var>. Since we know that we&#8217;ll want to filter our responses, it&#8217;s not a terrible idea to make a filter factory now and save it for later. In GeoTools everything is made using a factory. For filters, we need to make a factory using the new keyword, though. Here goes.\n<\/p>\n<blockquote><p>\npublic class WFSUpdater {<\/p>\n<p>&nbsp; &nbsp; private DataStore wfs;<br \/>\n&nbsp; &nbsp; private FilterFactory filterFactory;<\/p>\n<p>&nbsp; &nbsp; public WFSUpdater(String url) {<br \/>\n&nbsp; &nbsp; &nbsp; try {<br \/>\n&nbsp; &nbsp; &nbsp; &nbsp; URL endPoint = new URL(url);<\/p>\n<p>&nbsp; &nbsp; &nbsp; &nbsp; XMLSAXHandler.setLogLevel(Level.OFF); <font color=\"green\">\/\/ turns off logging for XML parsing.<\/font><\/p>\n<p>&nbsp; &nbsp; &nbsp; &nbsp; <font color=\"green\">\/\/ Parameters to connect to the WFS server, namely the URL.<br \/>\n&nbsp; &nbsp; &nbsp; &nbsp; \/\/ You could have others, say if you had to authenticate your connection with a username and password. <\/font><br \/>\n&nbsp; &nbsp; &nbsp; &nbsp; Map params = new HashMap();<br \/>\n&nbsp; &nbsp; &nbsp; &nbsp; params.put(WFSDataStoreFactory.URL.key, endPoint);<\/p>\n<p>&nbsp; &nbsp; &nbsp; &nbsp; wfs = (new WFSDataStoreFactory()).createNewDataStore(params);<br \/>\n&nbsp; &nbsp; &nbsp; &nbsp; filterFactory = FilterFactoryFinder.createFilterFactory();<\/p>\n<p>&nbsp; &nbsp; &nbsp; } catch (MalformedURLException e) {<br \/>\n&nbsp; &nbsp; &nbsp; &nbsp; e.printStackTrace();<br \/>\n&nbsp; &nbsp; &nbsp; } catch (IOException e) {<br \/>\n&nbsp; &nbsp; &nbsp; &nbsp; e.printStackTrace();<br \/>\n&nbsp; &nbsp; &nbsp; }<br \/>\n&nbsp; &nbsp; }<\/p>\n<\/blockquote>\n<p>\nNow that we have a connection, it&#8217;s time to make the transaction. As a first timer to GeoTools, I found it difficult to crawl through the documentation. Lots of their classes and methods have been deprecated with no clear hints about what to use instead. I had a hard time finding the right constructors. In what follows everything is hard-wired into the code, but it shouldn&#8217;t be all that bad to tweak things so that it works the way you like.\n<\/p>\n<blockquote><p>\npublic void updateProperty(String <font color=\"red\">propertyToUpdate<\/font>, String <font color=\"red\">updatedValue<\/font>) {<br \/>\n&nbsp; &nbsp; <font color=\"green\">\/\/ This is the layer name on the server.<\/font><br \/>\n&nbsp; &nbsp; String layer = &#8220;<font color=\"red\">myns:LayerToUpdate<\/font>&#8220;;<br \/>\n&nbsp; &nbsp; Transaction update = new DefaultTransaction(&#8220;update&#8221;); <font color=\"green\">\/\/ The handle\/ID of this transaction is called &#8220;update.&#8221; It&#8217;s required.<\/font><\/p>\n<p>&nbsp; &nbsp; try {<br \/>\n&nbsp; &nbsp; &nbsp; <font color=\"green\">\/\/ Make the filter.<\/font><br \/>\n&nbsp; &nbsp; &nbsp; Expression property = filterFactory.property(&#8220;<font color=\"red\">constraintProperty<\/font>&#8220;);<br \/>\n&nbsp; &nbsp; &nbsp; Expression value = filterFactory.literal(&#8220;<font color=\"red\">constraintValue<\/font>&#8220;);<br \/>\n&nbsp; &nbsp; &nbsp; Filter filter = filterFactory.equals(property, value);  <font color=\"green\">\/\/ This is an org.opengis.filter.Filter.<\/font><\/p>\n<p>&nbsp; &nbsp; &nbsp; FeatureStore features = (FeatureStore) wfs.getFeatureSource(layer);<\/p>\n<p>&nbsp; &nbsp; &nbsp; <font color=\"green\">\/\/ Set the transaction. Otherwise, we can&#8217;t commit our changes later on.<\/font><br \/>\n&nbsp; &nbsp; &nbsp; features.setTransaction(update);<\/p>\n<p>&nbsp; &nbsp; &nbsp; <font color=\"green\">\/\/ Fetch the property from the FeatureType schema so that we can update it with the new value.<\/font><br \/>\n&nbsp; &nbsp; &nbsp; FeatureType schema = features.getSchema();<br \/>\n&nbsp; &nbsp; &nbsp; AttributeType atrributeToUpdate = schema.getAttributeType(propertyToUpdate);    <\/p>\n<p>&nbsp; &nbsp; &nbsp; features.modifyFeatures(atrributeToUpdate, updatedValue, (org.geotools.filter.Filter) filter);  <font color=\"green\">\/\/ There&#8217;s that casting again.<\/font><\/p>\n<p>&nbsp; &nbsp; &nbsp; <font color=\"green\">\/\/ Record the modifications.<\/font><br \/>\n&nbsp; &nbsp; &nbsp; update.commit();<\/p>\n<p>&nbsp; &nbsp; &nbsp; } catch (IOException e) {<br \/>\n&nbsp; &nbsp; &nbsp; &nbsp; e.printStackTrace();<br \/>\n&nbsp; &nbsp; &nbsp; }<br \/>\n&nbsp; &nbsp; }<br \/>\n}\n<\/p><\/blockquote>\n<p>\nAnyway, I hope this saves some people the hassle of tearing through the Javadocs for GeoTools. Also, if there&#8217;s a better way to do what I did, <b>please<\/b> let me know. Happy GIS-ing.\n<\/p>\n<p><font size=\"1\" color=\"#999\">Technorati Tags: <a href=\"http:\/\/www.technorati.com\/tag\/geotools\" rel=\"tag\">geotools<\/a>, <a href=\"http:\/\/www.technorati.com\/tag\/geoserver\" rel=\"tag\">geoserver<\/a>, <a href=\"http:\/\/www.technorati.com\/tag\/opengis\" rel=\"tag\">opengis<\/a>, <a href=\"http:\/\/www.technorati.com\/tag\/ogc\" rel=\"tag\">ogc<\/a>, <a href=\"http:\/\/www.technorati.com\/tag\/java\" rel=\"tag\">java<\/a>, <a href=\"http:\/\/www.technorati.com\/tag\/wfs\" rel=\"tag\">wfs<\/a>, <a href=\"http:\/\/www.technorati.com\/tag\/wfs-t\" rel=\"tag\">wfs-t<\/a>, <a href=\"http:\/\/www.technorati.com\/tag\/shapefile\" rel=\"tag\">shapefile<\/a>, <a href=\"http:\/\/www.technorati.com\/tag\/update\" rel=\"tag\">update<\/a>, <a href=\"http:\/\/www.technorati.com\/tag\/request\" rel=\"tag\">request<\/a>, <a href=\"http:\/\/www.technorati.com\/tag\/javadoc\" rel=\"tag\">javadoc<\/a>, <a href=\"http:\/\/www.technorati.com\/tag\/gis\" rel=\"tag\">gis<\/a>, <a href=\"http:\/\/www.technorati.com\/tag\/esri\" rel=\"tag\">esri<\/a>, <a href=\"http:\/\/www.technorati.com\/tag\/xml\" rel=\"tag\">xml<\/a><\/font><\/p>\n","protected":false},"excerpt":{"rendered":"<p>A pet project of mine has flung me into the exciting though less-than-firm territory of web-backed geographical information systems. Since I don&#8217;t have the thousands of dollars it costs to get a commercial server like those provided by ESRI, I&#8217;ve &hellip; <a href=\"https:\/\/archive.blogs.harvard.edu\/jreyes\/2007\/08\/03\/geotools-wfs-t-update-request\/\">Continue reading <span class=\"meta-nav\">&rarr;<\/span><\/a><\/p>\n","protected":false},"author":102,"featured_media":0,"comment_status":"open","ping_status":"open","sticky":false,"template":"","format":"standard","meta":{"footnotes":""},"categories":[380,142],"tags":[],"class_list":["post-272","post","type-post","status-publish","format-standard","hentry","category-computer-science","category-technology"],"jetpack_featured_media_url":"","_links":{"self":[{"href":"https:\/\/archive.blogs.harvard.edu\/jreyes\/wp-json\/wp\/v2\/posts\/272","targetHints":{"allow":["GET"]}}],"collection":[{"href":"https:\/\/archive.blogs.harvard.edu\/jreyes\/wp-json\/wp\/v2\/posts"}],"about":[{"href":"https:\/\/archive.blogs.harvard.edu\/jreyes\/wp-json\/wp\/v2\/types\/post"}],"author":[{"embeddable":true,"href":"https:\/\/archive.blogs.harvard.edu\/jreyes\/wp-json\/wp\/v2\/users\/102"}],"replies":[{"embeddable":true,"href":"https:\/\/archive.blogs.harvard.edu\/jreyes\/wp-json\/wp\/v2\/comments?post=272"}],"version-history":[{"count":0,"href":"https:\/\/archive.blogs.harvard.edu\/jreyes\/wp-json\/wp\/v2\/posts\/272\/revisions"}],"wp:attachment":[{"href":"https:\/\/archive.blogs.harvard.edu\/jreyes\/wp-json\/wp\/v2\/media?parent=272"}],"wp:term":[{"taxonomy":"category","embeddable":true,"href":"https:\/\/archive.blogs.harvard.edu\/jreyes\/wp-json\/wp\/v2\/categories?post=272"},{"taxonomy":"post_tag","embeddable":true,"href":"https:\/\/archive.blogs.harvard.edu\/jreyes\/wp-json\/wp\/v2\/tags?post=272"}],"curies":[{"name":"wp","href":"https:\/\/api.w.org\/{rel}","templated":true}]}}