meface/docs/article/gis/openlayers/74wfscrud.md

1456 lines
53 KiB
Markdown
Raw Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

---
title: WFS服务的CRUD
date: 2020-11-25
author: ac
tags:
- wfs
- Openlayers
categories:
- GIS
---
> CRUD的原理
在Openlayers中对WFS服务CRUD的支持都封装在`ol.format.WFS`的解析器里面,查询使用其中的`writeGetFeature`方法创建查询要素的XML文本增加、修改、删除使用其中的`writeTransaction`方法创建事务的XML文本最后通过发送`POST`请求将XML文本发送到地图服务器进行CRUD的操作。
### 1 GetFeature
WFS的查询是通过`GetFeature`接口实现的。在发送`GetFeature`请求时使用Filter Encoding或CQL(Common Query Language)增加过滤的表达式,来筛选要素。
#### 1.1 CQL filters
在WFS GetFeature GET请求中可以使用cql_filter参数来指定ECQL(Extended Common Query Language)格式的过滤器,通过过滤器筛选符合条件的要素集。
CQL是OGC创建一种查询语言与基于xml的过滤器编码语言不同CQL使用熟悉的基于文本的语法编写。因此它更具可读性更易于编码。然而CQL也有一些局限性。例如它不能对id过滤器进行编码并且它要求在任何比较操作符的左侧都有一个属性。由于这个原因GeoServer提供了CQL的扩展版本称为ECQL。ECQL消除了CQL的限制提供了一种与SQL有更强相似性的更灵活的语言。
CQL和ECQL常用与`WMS`服务的`GetMap`请求和`WFS`的`GetFeature`请求中另外CQL还应用于SLD样式文件中。它们在功能上类似于SQL的“WHERE”子句。过滤器是使用条件指定的。
版本适用范围:
- Filter Encoding 1.0 适用于 WFS1.0和SLD1.0
- Filter Encoding 1.1 适用于 WFS1.1。ECQL完全适用于1.1的标准。
- Filter Encoding 2.0 适用于 WFS2.0
> Filter Encoding 是一种基于XML的过滤器编码语言。
示例:
```xml
<?xml version="1.0"?>
<wfs:GetFeature service="WFS" version="1.1.0"
xmlns:topp="http://www.openplans.org/topp"
xmlns:wfs="http://www.opengis.net/wfs"
xmlns:ogc="http://www.opengis.net/ogc"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://www.opengis.net/wfs
http://schemas.opengis.net/wfs/1.1.0/wfs.xsd">
<wfs:Query typeName="topp:states">
<ogc:Filter>
<ogc:FeatureId fid="states.3"/>
</ogc:Filter>
</wfs:Query>
</wfs:GetFeature>
```
<img src="./images/image854218.png" alt="image854218" style="zoom: 50%;" />
**比较运算符**
- `<PropertyIsEqualTo>`:等于
- `<PropertyIsNotEqualTo>`:不等于
- `<PropertyIsLessThan>`:小于
- `<PropertyIsLessThanOrEqualTo>`:小于或等于
- `<PropertyIsGreaterThan>`:大于
- `<PropertyIsGreaterThanOrEqualTo>`:大于或等于
- `<PropertyIsLike>`:模糊匹配
- `<PropertyIsNull>`不等于null
- `<PropertyIsBetween>`:在区间内
> 这些比较运算符中都包含两个元素,属性名称\<ogc:PropertyName>和属性值\<ogc:Literal>,根据版本不同会有所变化,但都是用于确定运算的属性和属性值。
**逻辑运算**
- `<And>` - 逻辑与
- `<Or>` - 逻辑或
- `<Not>` - 非
**空间运算**
- `<Intersects>` - 测试几何属性字段中几何要素是否与给定的几何要素相交
- `<Disjoint>` - 测试两个几何是否不相交
- `<Contains>` - 测试几何属性字段中几何要素是否包含给定的几何要素
- `<Within>` - 测试几何属性字段中几何要素是否在另一个给定的几何要素内
`Openlayers`将这些与`GetFeature`操作相关的过滤操作都封装在`ol.format.filter`命名空间下:
<div style="text-align:center"><img src="./images/image45038.png" alt="image45038" style="zoom: 80%;" /></div>
其中的`ol.format.filter.During`是用于比较日期的,如果要素表中存在日期字段或时间戳字段,在进行比较时,需要转成`ISO-8601`时间格式的字符串形式。
>2020年12月8日20点0分0秒可以写成带时区2020-12-08T20:00:00+08:00 或 20201208T200000+08
**Filter示例**
```html
<!doctype html>
<html >
<head>
<link rel="stylesheet" href="css/ol.css" type="text/css">
<style>
.map {
height: 85vh;
width: 100%;
}
</style>
<script src="lib/ol.js"></script>
<script src="lib/jquery-3.1.1.js"></script>
<title>OpenLayers example</title>
<meta charset="UTF-8">
</head>
<body>
<h2>OGC WFS服务加载GeoServer的WFS服务</h2>
<div id="map" class="map"></div>
<script type="text/javascript">
var inputPolygon = new ol.geom.Polygon([
//第一个LinearRing
[
[-8236070.085302306,4974636.883205217],
[-8234716.512732034,4974464.899891576],
[-8234716.512732034,4973573.134464388],
[-8236391.757990729,4973614.537951903],
[-8236070.085302306,4974636.883205217]
]
]);
var feature = new ol.Feature({
geometry:inputPolygon
})
var vec = new ol.source.Vector();
vec.addFeature(feature);
var wfsFormat = new ol.format.WFS();
var geojsonFormat = new ol.format.GeoJSON();
var vectorSource = new ol.source.Vector();
var wfsUrl = "http://localhost:8080/geoserver/wfs";
var getFeatureXml = wfsFormat.writeGetFeature({
"featureNS":"http://localhost:8080/test",//命名空间URI
"featurePrefix":"test",//命名空间的前缀
"featureTypes":["tiger_roads"],//图层名
"srsName":"EPSG:3857",//输出的要素集的空间参考
"outputFormat":"application/json",//输出格式
// "maxFeatures":"5",//最大要素数量
// "geometryName":"",//用于BBOX过滤的几何对象的名称
// "propertyNames":["state_name"],//属性数组,用于限定要素集中的要素有哪些属性
// "viewParams":"",//用于配置GeoServer中的视图参数
// "startIndex":"",//起始索引与count参数配置使用进行分页查询。WFS2.0.0后加入的功能)
// "count":"",//查询数量
// "bbox":"",//用于BBOX过滤的边界可以是Extent对象
// "resultType":""//用于指示WFS应该向用户返回结果(results返回所有要素实例,hits返回一个空的响应但有匹配的要素总数)
// "filter":new ol.format.filter.IsLike('name','W*','*','.','!'),//过滤表达式
// "filter":new ol.format.filter.Intersects('geom',intersectPolygon)
// "filter":new ol.format.filter.Contains('geom',intersectPolygon)
"filter":new ol.format.filter.Within('geom',inputPolygon)
});
/**
* jquery默认的Content-Type是application/x-www-form-urlencoded表单
* HTML文档标记text/html;
* 普通ASCII文档标记text/html;
* JPEG图片标记image/jpeg;
* GIF图片标记image/gif;
* js文档标记application/javascript;
* xml文件标记application/xml;text/xml的话将忽略xml数据里的编码格式
* 文件上传: multipart/form-data
* 普通表单application/x-www-form-urlencoded
*/
// $.ajax({
// url:wfsUrl,
// type:"post",
// contentType:"application/xml",
// processData:false,
// data:new XMLSerializer().serializeToString(getFeatureXml),
// dataType:"json",
// success:function (result) {
// console.log("result:" ,result);
// var featureCollection = geojsonFormat.readFeatures(result);
// vectorSource.addFeatures(featureCollection);
// },
// error:function(e){
// console.log("error:" ,e)
// }
// })
fetch(wfsUrl, {
method: 'POST',
body: new XMLSerializer().serializeToString(getFeatureXml),
})
.then(function (response) {
return response.json();
})
.then(function (result) {
var featureCollection = geojsonFormat.readFeatures(result);
vectorSource.addFeatures(featureCollection);
// map.getView().fit(vectorSource.getExtent());
// console.log("result:" , result);
});
var nyc = [-73.92722,40.774221];
var map = new ol.Map({
layers: [
// new ol.layer.Tile({
// source: new ol.source.OSM()
// }),
new ol.layer.Vector({
source:vectorSource
}),
new ol.layer.Vector({
source:vec,
style:new ol.style.Style({
stroke:new ol.style.Stroke({
color: 'rgba(255, 0, 255, 1.0)',
width: 2
})
})
})
],
target: 'map',
view: new ol.View({
center:ol.proj.fromLonLat(nyc),
zoom: 11
})
});
</script>
</body>
</html>
```
示例中创建了一个面作为空间运算的输入并创建对应的数据源和图层将其添加map中。通过`ol.format.WFS`中的`writeGetFeature()`方法创建`getFeature`操作的XML文本。再使用jquery或fetch发送`POST `请求获取要素集,最后使用对应的解析器解析响应结果,添加到矢量数据源中。
> jquery发送请求的Headers中的Content-Type默认是application/x-www-form-urlencoded表单当发送XML文本是需要将其指定为application/xml。而fetch()方法发送的请求会根据body中的数据自动设置Content-Type的类型。
当`outputFormat`参数设置为`application/json`时,请求结果会以`GeoJSON`的格式响应回来,可以使用`ol.format.GeoJSON`解析器进行解析。当`outputFormat`参数没有被设置时默认是以XML的形式返回可以使用`ol.format.WFS`解析器进行解析。
#### 1.2版本差异
1. 返回的GML版本不同
- WFS2.0.0请求默认返回的格式是GML3.2
- WFS1.1.0请求默认返回的格式是GML3
- WFS1.0.0请求默认返回的格式是GML2
2. GeoServer 对于每种支持的GML格式可以选择不同的SRS格式。
SRS Style对返回数据的轴顺序有影响对几何字段的坐标也会有影响。EPSG Code以格式EPSG:XXXX例如EPSG:4326返回典型的EPSG号。这会以经度/纬度x / y的顺序格式化地理坐标。
| 版本 | GML | SRS | Axis ordering |
| --------------------- | ------ | ------------------------------------------------------------ | ----------------------- |
| WFS1.0.0 | GML2 | OGC HTTP URL (http://www.opengis.net/gml/srs/epsg.xml#4326)或EPSG:xxxx | longitude/latitude(x/y) |
| WFS1.1.0 | GML3 | urn:x-ogc:def:crs:EPSG:xxxx | latitude/longitude(y/x) |
| WFS1.1.1<br>WFS 2.0.0 | GML3.2 | urn:x-ogc:def:crs:EPSG:xxxx | latitude/longitude(y/x) |
3. WFS 1.1.0和2.0.0支持动态重新投影数据这支持在本机SRS以外的SRS中返回数据。
4. WFS 2.0.0引入了新版本的过滤器编码规范,增加了对时间过滤器的支持。
5. WFS 2.0.0支持通过GetFeature请求进行联接。
6. WFS 2.0.0增加了通过startIndex和count参数分页GetFeature请求的结果的功能。GeoServer现在在WFS 1.0.0和1.1.0中支持此功能。
7. WFS 2.0.0支持存储的查询这是存储在服务器上的常规WFS查询因此可以通过将适当的标识符与WFS请求一起传递来调用它们。
8. WFS 2.0.0支持SOAP简单对象访问协议作为OGC接口的替代方法。
### 2 Transaction
在OWS规范中知道Web服务体系规范的HTTP接口参数有XML和KVP两种形式但WFS要求服务的`Transaction`接口必须由XML描述另外空间数据交互必须由GML进行数据过滤采用CQL语言。
每个事务将由零个或多个插入、更新和删除元素组成,每个事务元素按顺序执行。
> 在GeoServer中每个事务都是原子的这意味着如果任何元素失败事务就会被放弃数据也不会被修改。支持事务的WFS服务器有时称为WFS- t服务器。GeoServer完全支持事务。
#### 2.1 GML
地理标记语言(GML)是一种用于表示地理特征的XML语法。GML是地理系统的建模语言也是Internet上地理事务的开放交换格式。与大多数基于XML的语法一样语法分为两部分——描述文档的`schema`模式和包含实际数据的实例文档。
<img src="./images/image753.png" alt="image753" style="zoom: 67%;" />
<div style="text-align:center">GML2 中Geometry schema的UML图</div>
其中`<coord>`是坐标`<coordinates>`的子元素,用于描述坐标值。还添加了`<Box>`用于描述一个范围 extent坐标值为范围的左下角最小值和右上角最大值点。
`GML2`中几何标签的示例:
1. Coordinates
```xml
<coordinates decimal="." cs="," ts=" ">
1.03,2.167 4.167,2.34
</coordinates>
```
等价于
```xml
<coord><X>1.03</X><Y>2.167</Y></coord>
<coord><X>4.167</X><Y>2.34</Y></coord>
```
注意:坐标值必须是相同的维度。
- cscoordinate separated坐标之间的分隔符
- ts(tuples separated):坐标元组之间分隔符;
2. Point
```xml
<Point srsName="http://www.opengis.net/gml/srs/epsg.xml#4326">
<coordinates>5.0,40.0</coordinates>
</Point>
```
Point 标签下面可以有 coordinates 标签用于描述点位信息。还可以使用ID、srsName 属性srsName 指定要素的空间参考。
3. Box
```xml
<Box srsName="EPSG:4326">
<coordinates>
0.0,0.0 100.0,100.0
</coordinates>
</Box>
```
Box用于描述一个范围 extent,坐标值为范围的左下角(最小值)和右上角(最大值)点。
4. LineString
```xml
<LineString srsName="EPSG:4326">
<coordinates>
0.0,0.0
100.0,100.0
</coordinates>
</LineString>
```
LineString是一个分段的线状路径用于描述线要素至少两个点。
5. LinearRing
```xml
<LinearRing>
<coordinates>
0.0,0.0
100.0,0.0
50.0,100.0
0.0,0.0
</coordinates>
</LinearRing>
```
是一段封闭的分段的线状路径coordinates 标签中至少4个坐标点三个坐标可以确定 LinearRing第四个坐标用于闭合与第一个坐标相同。用于构造面元素Polygon所以不需要SRS属性。
6. Polygon
```xml
<Polygon srsName="EPSG:4326">
<outerBoundaryIs>
<LinearRing>
<coordinates>
0.0,0.0 100.0,0.0 100.0,100.0 0.0,100.0
0.0,0.0
</coordinates>
</LinearRing>
</outerBoundaryIs>
<innerBoundaryIs>
<LinearRing>
<coordinates>
10.0,10.0 10.0,40.0 40.0,40.0 40.0,10.0
10.0,10.0
</coordinates>
</LinearRing>
</innerBoundaryIs>
<innerBoundaryIs>
<LinearRing>
<coordinates>
60.0,60.0 60.0,90.0 90.0,90.0 90.0,60.0
60.0,60.0
</coordinates>
</LinearRing>
</innerBoundaryIs>
</Polygon>
```
用于描述面要素surface。必须有一个且最多只有一个 Exterior boundary 和 零个或多个 Interior boundary。Interior boundary 之间不能相交或包含。路径(坐标)的顺序是顺时针或逆时针不重要。
7. MultiPoint
```xml
<MultiPoint srsName="EPSG:4326">
<pointMember>
<Point>
<coordinates>56.1,0.45</coordinates>
</Point>
</pointMember>
<pointMember>
<Point>
<coordinates>46.71,9.25</coordinates>
</Point>
</pointMember>
<pointMember>
<Point>
<coordinates>56.88,10.44</coordinates>
</Point>
</pointMember>
</MultiPoint >
```
> 注意srsName 属性只能出现在最外层要素的标签内,且其包含的子要素不能再出现 srsName属性。
8. MultiLineString
```xml
<MultiLineString srsName="EPSG:4326">
<lineStringMember>
<LineString>
<coordinates>56.1,0.45 67.23,0.67</coordinates>
</LineString>
</lineStringMember>
<lineStringMember>
<LineString>
<coordinates>46.71,9.25 56.88,10.44</coordinates>
</LineString>
</lineStringMember>
<lineStringMember>
<LineString>
<coordinates>324.1,219.7 0.45,0.56</coordinates>
</LineString>
</lineStringMember>
</MultiLineString>
```
注意:跟 MuliPointElement 标签一样srsName 属性只能出现在最外层要素上。
9. MultiPolygon
```xml
<MultiPolygon srsName="EPSG:4326">
<polygonMember>
<Polygon>
<outerBoundaryIs>
<LinearRing>
<coordinates>
0.0,0.0 10.0,0.0 10.0,10.0 0.0,10.0
0.0,0.0
</coordinates>
</LinearRing>
</outerBoundaryIs>
</Polygon>
</polygonMember>
<polygonMember>
<Polygon>
<outerBoundaryIs>
<LinearRing>
<coordinates>
40.0,40.0 50.0,40.0 50.0,50.0 40.0,50.0
40.0,40.0
</coordinates>
</LinearRing>
</outerBoundaryIs>
</Polygon>
</polygonMember>
</MultiPolygon>
```
10. GeometryCollection
```xml
<GeometryCollection srsName="EPSG:4326">
<geometryMember>
<Point>
<coordinates>
50.0,50.0
</coordinates>
</Point>
</geometryMember>
<geometryMember>
<LineString>
<coordinates>
0.0,0.0 0.0,50.0 100.0,50.0 100.0,100.0
</coordinates>
</LineString>
</geometryMember>
<geometryMember>
<Polygon>
<outerBoundaryIs>
<LinearRing>
<coordinates>
0.0,0.0 100.0,0.0 50.0,100.0 0.0,0.0
</coordinates>
</LinearRing>
</outerBoundaryIs>
</Polygon>
</geometryMember>
</GeometryCollection>
```
geometryMember 子标签可以包含任意类型的几何对象。
#### 2.2 Insert
使用`<Insert>`标签创建一个新的要素添加到WFS服务的数据源中。默认是使用`GML3`(WFS1.1.0)来描述要创建的新要素,也可以使用`inputFormat`属性来兼容旧的`GML2`(inputFormat='text/xml;subtype=2.1.2')。当新的要素添加到数据源中时,会默认给新生的要输生成一个`gid`作为唯一标识来标识该要素。若想指定`gid`的值,可以只用`idgen`属性,将其设置为`UseExisting`,在插入的要素标签中添加`gml:id`属性指定`gid`的值,如果所给的值已经存在或数据类型不匹配,则会插入失败。
```xml
<?xml version="1.0"?>
<wfs:Transaction
version="1.1.0"
service="WFS"
xmlns="http://www.someserver.com/myns"
xmlns:gml="http://www.opengis.net/gml"
xmlns:ogc="http://www.opengis.net/ogc"
xmlns:test="http://localhost:8080/test"
xmlns:wfs="http://www.opengis.net/wfs"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://www.someserver.com/myns
http://www.someserver.com/wfs/cwwfs.cgi?
http://www.opengis.net/wfs ../wfs/1.1.0/WFS.xsd">
<wfs:Insert inputFormat="text/xml;subtype=2.1.2" idgen="UseExisting">
<test:tiger_roads gml:id="10002">
<cfcc>A94</cfcc>
<name>测试</name>
<geom>
<MultiLineString srsName="EPSG:3857">
<lineStringMember>
<LineString>
<coordinates>-8237795.685217111,4980323.905513588 -8238827.585098961,4978584.963120101</coordinates>
</LineString>
</lineStringMember>
</MultiLineString>
</geom>
</test:tiger_roads>
</wfs:Insert>
</wfs:Transaction>
```
<img src="./images/image9076.png" alt="image9076" style="zoom: 80%;" />
> PostGIS导入的shapefile文件的srid默认为0。新增加的要素带有空间参考srid所以如果在导入文件的时候没有指定srid则会不一致新增的要素在PostgreSQL的几何查看器中显示不出来。
可能出现的问题:`is read-only`
解决方法放开write权限。在GeoServer左侧的"Security"中的"Data"栏,点击"Rule path"中的"..w",勾选"Grant access to any role"下面的单选框,点击保存。
```xml
<?xml version="1.0" encoding="UTF-8"?>
<ows:ExceptionReport xmlns:xs="http://www.w3.org/2001/XMLSchema" xmlns:ows="http://www.opengis.net/ows" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" version="1.0.0" xsi:schemaLocation="http://www.opengis.net/ows http://localhost:8080/geoserver/schemas/ows/1.0.0/owsExceptionReport.xsd">
<ows:Exception exceptionCode="NoApplicableCode">
<ows:ExceptionText>{http://localhost:8080/test}tiger_roads is read-only</ows:ExceptionText>
</ows:Exception>
</ows:ExceptionReport>
```
在`writeTransaction`方法中笔者没有查找到关于`idgen`属性的配置方式直接在创建Feature实例时添加`gid`是无效的,`gid`的生成方式是由服务端自动生成。
```html
<!doctype html>
<html >
<head>
<link rel="stylesheet" href="css/ol.css" type="text/css">
<style>
.map {
height: 85vh;
width: 100%;
}
</style>
<script src="lib/ol.js"></script>
<script src="lib/jquery-3.1.1.js"></script>
<title>OpenLayers example</title>
<meta charset="UTF-8">
</head>
<body>
<h2>OGC WFS服务Transaction Insert</h2>
<div id="map" class="map"></div>
<script type="text/javascript">
var vectorSource = new ol.source.Vector({
format: new ol.format.GeoJSON(),
loader: function(extent, resolution, projection) {
var proj = projection.getCode();
var url = 'http://localhost:8080/geoserver/wfs?service=WFS&' +
'version=1.1.0&request=GetFeature&typename=test:tiger_roads&' +
'outputFormat=application/json&srsname='+proj+'&' +
'bbox=' + extent.join(',') + ',' +proj;
var xhr = new XMLHttpRequest();
xhr.open('GET', url);
var onError = function() {
vectorSource.removeLoadedExtent(extent);
}
xhr.onerror = onError;
xhr.onload = function() {
if (xhr.status == 200) {
vectorSource.addFeatures(
vectorSource.getFormat().readFeatures(xhr.responseText));
} else {
onError();
}
}
xhr.send();
},
strategy: ol.loadingstrategy.bbox
});
var nyc = [-73.92722,40.774221];
var map = new ol.Map({
layers: [
// new ol.layer.Tile({
// source: new ol.source.OSM()
// }),
new ol.layer.Vector({
source: vectorSource
})
],
target: 'map',
view: new ol.View({
center:ol.proj.fromLonLat(nyc),
zoom: 11
})
})
map.on("click",function (e) {
var point = e.coordinate;
console.log("x:"+point[0]+",y:"+point[1]);
});
//Transaction Insert
var insertGeo = new ol.Feature({
// gid:10006,//无效服务会自动生成gid
cfcc:"A95",
name:"测试Insert4",
geom: new ol.geom.MultiLineString([
[
[-8235005.193364706,4986963.973958403],
[-8238062.674496112,4982377.752261292]
]
])
});
insertGeo.setGeometryName('geom');
var wfsUrl = "http://localhost:8080/geoserver/wfs";
var wfsFormat = new ol.format.WFS();
var session = wfsFormat.writeTransaction([insertGeo],null,null,{
featureNS:"http://localhost:8080/test",
featurePrefix:"test",
featureType:"tiger_roads",
srsName:"EPSG:3857"
});
$.ajax({
url:wfsUrl,
type:"post",
contentType:"application/xml",
processData:false,
data:new XMLSerializer().serializeToString(session),
success:function (result) {
var responseText = wfsFormat.readTransactionResponse(result);
console.log(responseText)
},
error:function(e){
console.log("error:" ,e)
}
})
</script>
</body>
</html>
```
#### 2.3 Update
`<update>`标签用于修改单个Feature要素或要素集合多个`<update>`标签可以出现在同一个`Transaction`事务里面。`<update>`标签里面包含一个或多个用于指定要修改的属性的`<Property>`标签和一个用于筛选要素的`<Filter>`标签,对于没有使用`<Property`属性列出来的属性将不会改变但如果只指定了属性名没有给属性值则该属性值会被设置为null
```xml
<?xml version="1.0"?>
<wfs:Transaction
version="1.1.0"
service="WFS"
xmlns="http://www.someserver.com/myns"
xmlns:gml="http://www.opengis.net/gml"
xmlns:ogc="http://www.opengis.net/ogc"
xmlns:test="http://localhost:8080/test"
xmlns:wfs="http://www.opengis.net/wfs"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://www.someserver.com/myns
http://www.someserver.com/wfs/cwwfs.cgi?
http://www.opengis.net/wfs ../wfs/1.1.0/WFS.xsd">
<wfs:Update typeName="tiger_roads">
<wfs:Property>
<wfs:Name>name</wfs:Name>
<wfs:Value>测试Insert412</wfs:Value>
</wfs:Property>
<ogc:Filter>
<ogc:PropertyIsLike wildCard="*" singleChar="." escape="!">
<ogc:PropertyName>test:name</ogc:PropertyName>
<ogc:Literal>测试Insert4*</ogc:Literal>
</ogc:PropertyIsLike>
</ogc:Filter>
</wfs:Update>
</wfs:Transaction>
```
从上面的示例中可以看出发送Transaction事务的XML文本可以实现类似于SQL语句一样的`Update`操作但在`writeTransaction`方法中并没有提供类似`Filter`过滤的参数而是直接将需要修改的Feature要素作为输入进行修改通常的作法是
1. 先加载WFS服务
2. 在通过`ol.interaction.Select``ol.interaction.Modify`控件选择WFS服务的要素并对其进行修改监听修改完的事件获取要素修改后的`geometry`及其属性
3. 还可以提供一个表单或弹出层界面来修改属性值
4. 将最终修改得到的要素传入`writeTransaction`方法创建事务的XML文本发送请求提交
```html
<!doctype html>
<html>
<head>
<link rel="stylesheet" href="css/ol.css" type="text/css">
<link rel="stylesheet" href="css/layui.css" type="text/css">
<style>
.map {
height: 85vh;
width: 100%;
}
</style>
<script src="lib/jquery-3.1.1.js"></script>
<script src="lib/layer.js"></script>
<script src="lib/ol.js"></script>
<title>OpenLayers example</title>
<meta charset="UTF-8">
</head>
<body>
<h2>OGC WFS服务Transaction Update</h2>
<div id="map" class="map"></div>
<script type="text/javascript">
var vectorSource = new ol.source.Vector({
format: new ol.format.GeoJSON({geometryName:"geom"}),
loader: function (extent, resolution, projection) {
var proj = projection.getCode();
var url = 'http://localhost:8080/geoserver/wfs?service=WFS&' +
'version=1.1.0&request=GetFeature&typename=test:tiger_roads&' +
'outputFormat=application/json&srsname=' + proj + '&' +
'bbox=' + extent.join(',') + ',' + proj;
var xhr = new XMLHttpRequest();
xhr.open('GET', url);
var onError = function () {
vectorSource.removeLoadedExtent(extent);
}
xhr.onerror = onError;
xhr.onload = function () {
if (xhr.status == 200) {
vectorSource.addFeatures(
vectorSource.getFormat().readFeatures(xhr.responseText));
} else {
onError();
}
}
xhr.send();
},
strategy: ol.loadingstrategy.bbox
});
var nyc = [-73.92722, 40.774221];
var map = new ol.Map({
layers: [
// new ol.layer.Tile({
// source: new ol.source.OSM()
// }),
new ol.layer.Vector({
source: vectorSource
})
],
target: 'map',
view: new ol.View({
center: ol.proj.fromLonLat(nyc),
zoom: 11
})
})
map.on("click", function (e) {
var point = e.coordinate;
console.log("x:" + point[0] + ",y:" + point[1]);
});
//Transaction update
var modfeatureCollection = null;
var select = new ol.interaction.Select({
//点击选择要素的容差单位px
hitTolerance: 5,
//设置select选择或释放触发的切换函数
toggleCondition: function (e) {
if (modfeatureCollection&&modfeatureCollection.getLength()) {
var modFeature = modfeatureCollection.item(0);
showProperty(modFeature);
}
}
});
var modify = new ol.interaction.Modify({
features: select.getFeatures()
});
//每增加或移动要素的一个节点都会触发
modify.on('modifyend', function (e) {
modfeatureCollection = e.features;
});
map.addInteraction(select);
map.addInteraction(modify);
function showProperty(feature) {
var text = createForm(feature);
layer.open({
title: '属性编辑'
, content: text
, type: 1
, btn: ['提交']
, yes: function (index, layero) {
var property = feature.values_;
var geometryName = feature.getGeometryName();
for(var key in property){
if(key != geometryName){
var newVal = document.getElementById(key).value;
property[key] = newVal;
}
}
updateFeature(feature);
layer.close(index);
}
})
}
function createForm(feature) {
var divStr = '<div class="layui-form">';
var property = feature.values_;
var geometryName = feature.getGeometryName();
for(var key in property){
if(key != geometryName){
divStr += '<div class="layui-form-item">'+
'<label class="layui-form-label">'+ key+'</label>'+
'<div class="layui-input-block">'+
'<input type="text" id="'+ key+'" value="'+property[key]+'" class="layui-input">'+
'</div>'+
'</div>';
}
}
divStr += '</div>';
return divStr
}
function updateFeature(feature) {
var wfsUrl = "http://localhost:8080/geoserver/wfs";
var geometryName = feature.getGeometryName();
var wfsFormat = new ol.format.WFS({geometryName:geometryName});
var transactionXML = wfsFormat.writeTransaction(null,[feature],null,{
featureNS:"http://localhost:8080/test",
featurePrefix:"test",
featureType:"tiger_roads",
srsName:"EPSG:3857"
});
var xhr = new XMLHttpRequest();
xhr.open('POST', wfsUrl);
xhr.onerror = function(e){
console.log("修改失败!",e);
};
xhr.onload = function() {
if (xhr.status == 200) {
var result = wfsFormat.readTransactionResponse(xhr.responseText);
console.log(result);
}else{
console.log("修改失败!",xhr.responseText);
}
}
xhr.setRequestHeader("Content-Type","application/xml");
xhr.send(new XMLSerializer().serializeToString(transactionXML));
}
</script>
</body>
</html>
```
修改的要素必须要有id因为最终发送的Transaction的XML文本中是通过`GmlObjectId`作为过滤表达式Filter筛选要素的
> 修改操作需要注意,字段的类型。如果所给的属性值于字段类型不匹配或长度越界了,将会修改失败。
#### 2.4 Delete
`<Delete>`用于删除一个或多个要素`<Insert>`、`<Update>`标签一样通过`<Filter>`标签筛选要操作的要素。如果没有使用`<Filter>`标签对要素进行筛选,则该事务中的删除操作将无效。
```xml
<Transaction xmlns="http://www.opengis.net/wfs" service="WFS" version="1.1.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://www.opengis.net/wfs http://schemas.opengis.net/wfs/1.1.0/wfs.xsd">
<Delete typeName="test:tiger_roads" xmlns:test="http://localhost:8080/test">
<Filter xmlns="http://www.opengis.net/ogc">
<FeatureId fid="tiger_roads.8339"/>
</Filter>
</Delete>
</Transaction>
```
删除操作和更新操作一样也是根据Feature的id来进行操作的。这里我们使用`ol.interaction.Select`控件来选择要删除的要素,在确定删除操作成功后,从矢量数据源中移除被删除的要素和清空在`Select`控件中已选要素的集合。
```html
<!doctype html>
<html>
<head>
<link rel="stylesheet" href="css/ol.css" type="text/css">
<link rel="stylesheet" href="css/layui.css" type="text/css">
<style>
.map {
height: 85vh;
width: 100%;
}
</style>
<script src="lib/jquery-3.1.1.js"></script>
<script src="lib/layer.js"></script>
<script src="lib/ol.js"></script>
<title>OpenLayers example</title>
<meta charset="UTF-8">
</head>
<body>
<h2>OGC WFS服务Transaction Delete</h2>
<div id="map" class="map"></div>
<script type="text/javascript">
var vectorSource = new ol.source.Vector({
format: new ol.format.GeoJSON({geometryName:"geom"}),
loader: function (extent, resolution, projection) {
var proj = projection.getCode();
var url = 'http://localhost:8080/geoserver/wfs?service=WFS&' +
'version=1.1.0&request=GetFeature&typename=test:tiger_roads&' +
'outputFormat=application/json&srsname=' + proj + '&' +
'bbox=' + extent.join(',') + ',' + proj;
var xhr = new XMLHttpRequest();
xhr.open('GET', url);
var onError = function () {
vectorSource.removeLoadedExtent(extent);
}
xhr.onerror = onError;
xhr.onload = function () {
if (xhr.status == 200) {
vectorSource.addFeatures(
vectorSource.getFormat().readFeatures(xhr.responseText));
} else {
onError();
}
}
xhr.send();
},
strategy: ol.loadingstrategy.bbox
});
var nyc = [-73.92722, 40.774221];
var map = new ol.Map({
layers: [
// new ol.layer.Tile({
// source: new ol.source.OSM()
// }),
new ol.layer.Vector({
source: vectorSource
})
],
target: 'map',
view: new ol.View({
center: ol.proj.fromLonLat(nyc),
zoom: 11
})
})
//Transaction update
var select = new ol.interaction.Select({
//点击选择要素的容差单位px
hitTolerance: 5
});
map.addInteraction(select);
select.on("select",function(e){
//获取当前所选的要素集
var selectFeatures = e.selected;
if(selectFeatures.length){
layer.open({
title:"提示"
,content:"确定删除【"+selectFeatures[0].getProperties().name+"】!"
,btn:["确定"]
, yes: function (index, layero) {
deleteFeatures(selectFeatures);
layer.close(index);
}
});
}
});
function deleteFeatures(features) {
var wfsUrl = "http://localhost:8080/geoserver/wfs";
var geometryName = features[0].getGeometryName();
var wfsFormat = new ol.format.WFS({geometryName:geometryName});
var transactionXML = wfsFormat.writeTransaction(null,null,features,{
featureNS:"http://localhost:8080/test",
featurePrefix:"test",
featureType:"tiger_roads",
srsName:"EPSG:3857"
});
var xhr = new XMLHttpRequest();
xhr.open('POST', wfsUrl);
xhr.onerror = function(e){
console.log("删除失败!",e);
};
xhr.onload = function() {
if (xhr.status == 200) {
var result = wfsFormat.readTransactionResponse(xhr.responseText);
console.log(result);
vectorSource.removeFeature(features[0]);
select.getFeatures().clear()
}else{
console.log("删除失败!",xhr.responseText);
}
}
xhr.setRequestHeader("Content-Type","application/xml");
xhr.send(new XMLSerializer().serializeToString(transactionXML));
}
</script>
</body>
</html>
```
### 3 WFS运算示例
> WFS版本使用1.1.0
#### 3.1 简单查询
1. 查询该服务(图层)的所有要素
```xml
<?xml version="1.0"?>
<wfs:GetFeature service="WFS" version="1.1.0"
xmlns:topp="http://www.openplans.org/topp"
xmlns:wfs="http://www.opengis.net/wfs"
xmlns:ogc="http://www.opengis.net/ogc"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://www.opengis.net/wfs
http://schemas.opengis.net/wfs/1.1.0/wfs.xsd">
<wfs:Query typeName="topp:states"></wfs:Query>
</wfs:GetFeature>
```
2. 指定返回的结果集中要素的属性属性名称需要大写XML是大小写敏感的且需要添加工作空间
```xml
<?xml version="1.0"?>
<wfs:GetFeature service="WFS" version="1.1.0"
xmlns:topp="http://www.openplans.org/topp"
xmlns:wfs="http://www.opengis.net/wfs"
xmlns:ogc="http://www.opengis.net/ogc"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://www.opengis.net/wfs
http://schemas.opengis.net/wfs/1.1.0/wfs.xsd">
<wfs:Query typeName="topp:states">
<wfs:PropertyName>topp:STATE_NAME</wfs:PropertyName>
</wfs:Query>
</wfs:GetFeature>
```
3. 指定响应数据的格式
```xml
<?xml version="1.0"?>
<wfs:GetFeature service="WFS" version="1.1.0"
outputFormat="application/json"
xmlns:topp="http://www.openplans.org/topp"
xmlns:wfs="http://www.opengis.net/wfs"
xmlns:ogc="http://www.opengis.net/ogc"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://www.opengis.net/wfs
http://schemas.opengis.net/wfs/1.1.0/wfs.xsd">
<wfs:Query typeName="topp:states">
<wfs:PropertyName>topp:STATE_NAME</wfs:PropertyName>
</wfs:Query>
</wfs:GetFeature>
```
4. 查询多个服务(图层)
```xml
<?xml version="1.0"?>
<wfs:GetFeature service="WFS" version="1.1.0"
xmlns:topp="http://www.openplans.org/topp"
xmlns:wfs="http://www.opengis.net/wfs"
xmlns:ogc="http://www.opengis.net/ogc"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://www.opengis.net/wfs
http://schemas.opengis.net/wfs/1.1.0/wfs.xsd">
<wfs:Query typeName="topp:states"></wfs:Query>
<wfs:Query typeName="tiger:tiger_roads"></wfs:Query>
</wfs:GetFeature>
```
#### 3.2 比较运算
比较运算符可以说是表达式应该放在Filter标签里面
1. 查找哪个州的总人口person等于3145585.0
```xml
<?xml version="1.0"?>
<wfs:GetFeature service="WFS" version="1.1.0"
xmlns:topp="http://www.openplans.org/topp"
xmlns:wfs="http://www.opengis.net/wfs"
xmlns:ogc="http://www.opengis.net/ogc"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://www.opengis.net/wfs
http://schemas.opengis.net/wfs/1.1.0/wfs.xsd">
<wfs:Query typeName="topp:states">
<ogc:Filter>
<ogc:PropertyIsEqualTo>
<ogc:PropertyName>topp:PERSONS</ogc:PropertyName>
<ogc:Literal>3145585.0</ogc:Literal>
</ogc:PropertyIsEqualTo>
</ogc:Filter>
</wfs:Query>
</wfs:GetFeature>
```
2. 模糊匹配州名称以W开头的
```xml
<?xml version="1.0"?>
<wfs:GetFeature service="WFS" version="1.1.0"
outputFormat="application/json"
xmlns:topp="http://www.openplans.org/topp"
xmlns:wfs="http://www.opengis.net/wfs"
xmlns:ogc="http://www.opengis.net/ogc"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://www.opengis.net/wfs
http://schemas.opengis.net/wfs/1.1.0/wfs.xsd">
<wfs:Query typeName="topp:states">
<ogc:Filter>
<ogc:PropertyIsLike wildCard="*" singleChar="." escape="!">
<ogc:PropertyName>topp:STATE_NAME</ogc:PropertyName>
<ogc:Literal>W*</ogc:Literal>
</ogc:PropertyIsLike>
</ogc:Filter>
</wfs:Query>
</wfs:GetFeature>
```
wildCard :指定匹配零个或多个字符串字符的任何序列的模式字符
singleChar :指定匹配任何单个字符串字符的模式字符
escapeChar :指定可用于转义模式字符的转义字符
3. 查询state_name属性为null的记录
```xml
<?xml version="1.0"?>
<wfs:GetFeature service="WFS" version="1.1.0"
outputFormat="application/json"
xmlns:topp="http://www.openplans.org/topp"
xmlns:wfs="http://www.opengis.net/wfs"
xmlns:ogc="http://www.opengis.net/ogc"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://www.opengis.net/wfs
http://schemas.opengis.net/wfs/1.1.0/wfs.xsd">
<wfs:Query typeName="topp:states">
<ogc:Filter>
<ogc:PropertyIsNull>
<ogc:PropertyName>topp:STATE_NAME</ogc:PropertyName>
</ogc:PropertyIsNull>
</ogc:Filter>
</wfs:Query>
</wfs:GetFeature>
```
4. 查询人口总数在[2477574,4781468]之间的州并根据总人口persons属性倒序排序
```xml
<?xml version="1.0"?>
<wfs:GetFeature service="WFS" version="1.1.0"
outputFormat="application/json"
xmlns:test="http://localhost:8080/test"
xmlns:wfs="http://www.opengis.net/wfs"
xmlns:ogc="http://www.opengis.net/ogc"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://www.opengis.net/wfs
http://schemas.opengis.net/wfs/1.1.0/wfs.xsd">
<wfs:Query typeName="test:states">
<wfs:PropertyName>test:persons</wfs:PropertyName>
<ogc:Filter>
<ogc:PropertyIsBetween>
<ogc:PropertyName>test:persons</ogc:PropertyName>
<ogc:LowerBoundary><ogc:Literal>2477574</ogc:Literal></ogc:LowerBoundary>
<ogc:UpperBoundary><ogc:Literal>4781468</ogc:Literal></ogc:UpperBoundary>
</ogc:PropertyIsBetween>
</ogc:Filter>
<ogc:SortBy>
<ogc:SortProperty>
<ogc:PropertyName>test:persons</ogc:PropertyName>
<ogc:SortOrder>DESC</ogc:SortOrder>
</ogc:SortProperty>
</ogc:SortBy>
</wfs:Query>
</wfs:GetFeature>
```
注意:
- 需要将state的shapefile文件导入postgresql中发布postgis表的数据图层否则将会因为无法序列化而不能排序
- 入库后postgresql表中的属性字段是默认小写的所以PropertyName标签中的属性值应小写
- 用于排序的字段必须是结果集中存在的字段,即存在标签\<wfs:PropertyName>值为排序属性
#### 3.3空间运算
1. Intersects相交
```xml
<?xml version="1.0"?>
<wfs:GetFeature service="WFS" version="1.1.0"
outputFormat="application/json"
xmlns:test="http://localhost:8080/test"
xmlns:wfs="http://www.opengis.net/wfs"
xmlns:ogc="http://www.opengis.net/ogc"
xmlns:gml="http://www.opengis.net/gml"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://www.opengis.net/wfs
http://schemas.opengis.net/wfs/1.1.0/wfs.xsd">
<wfs:Query typeName="test:tiger_roads">
<wfs:PropertyName>test:cfcc</wfs:PropertyName>
<wfs:PropertyName>test:name</wfs:PropertyName>
<ogc:Filter>
<Intersects>
<PropertyName>geom</PropertyName>
<gml:Envelope srsName="http://www.opengis.net/def/crs/EPSG/0/3857">
<gml:lowerCorner>-8236751.648901709 4974597.071767016</gml:lowerCorner>
<gml:upperCorner>-8235757.967534002 4975476.097592296</gml:upperCorner>
</gml:Envelope>
</Intersects>
</ogc:Filter>
</wfs:Query>
</wfs:GetFeature>
```
![image55382](./images/image55382.png)
2. Disjoint不相交。下面将逻辑运算和空间运算结合取不相交的非得到与上面1一样的结果
```xml
<?xml version="1.0"?>
<wfs:GetFeature service="WFS" version="1.1.0"
outputFormat="application/json"
xmlns:test="http://localhost:8080/test"
xmlns:wfs="http://www.opengis.net/wfs"
xmlns:ogc="http://www.opengis.net/ogc"
xmlns:gml="http://www.opengis.net/gml"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://www.opengis.net/wfs
http://schemas.opengis.net/wfs/1.1.0/wfs.xsd">
<wfs:Query typeName="test:tiger_roads">
<wfs:PropertyName>test:cfcc</wfs:PropertyName>
<wfs:PropertyName>test:name</wfs:PropertyName>
<ogc:Filter>
<Not>
<Disjoint>
<PropertyName>geom</PropertyName>
<gml:Envelope srsName="http://www.opengis.net/def/crs/EPSG/0/3857">
<gml:lowerCorner>-8236751.648901709 4974597.071767016</gml:lowerCorner>
<gml:upperCorner>-8235757.967534002 4975476.097592296</gml:upperCorner>
</gml:Envelope>
</Disjoint>
</Not>
</ogc:Filter>
</wfs:Query>
</wfs:GetFeature>
```
3. Contains判断几何对象是否包含另一个几何几何属性的要素是否包含所给的几何对象
```xml
<?xml version="1.0"?>
<wfs:GetFeature service="WFS" version="1.1.0"
outputFormat="application/json"
xmlns:test="http://localhost:8080/test"
xmlns:wfs="http://www.opengis.net/wfs"
xmlns:ogc="http://www.opengis.net/ogc"
xmlns:gml="http://www.opengis.net/gml"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://www.opengis.net/wfs
http://schemas.opengis.net/wfs/1.1.0/wfs.xsd">
<wfs:Query typeName="test:tiger_roads">
<wfs:PropertyName>test:cfcc</wfs:PropertyName>
<wfs:PropertyName>test:name</wfs:PropertyName>
<ogc:Filter>
<Intersects>
<PropertyName>geom</PropertyName>
<gml:Point srsName="http://www.opengis.net/def/crs/EPSG/0/3857">
<gml:pos>-8234663.297809127 4976806.185109221</gml:pos>
</gml:Point>
</Intersects>
</ogc:Filter>
</wfs:Query>
</wfs:GetFeature>
```
常见的包含关系存在于线包含点,面包含线。
4. Within判断几何属性字段中的几何要素是否被给定的另一个几何对象包含
```xml
<?xml version="1.0"?>
<wfs:GetFeature service="WFS" version="1.1.0"
outputFormat="application/json"
xmlns:test="http://localhost:8080/test"
xmlns:wfs="http://www.opengis.net/wfs"
xmlns:ogc="http://www.opengis.net/ogc"
xmlns:gml="http://www.opengis.net/gml"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://www.opengis.net/wfs
http://schemas.opengis.net/wfs/1.1.0/wfs.xsd">
<wfs:Query typeName="test:tiger_roads">
<wfs:PropertyName>test:cfcc</wfs:PropertyName>
<wfs:PropertyName>test:name</wfs:PropertyName>
<ogc:Filter>
<Within>
<PropertyName>geom</PropertyName>
<gml:Polygon srsName="http://www.opengis.net/def/crs/EPSG/0/3857">
<gml:exterior>
<gml:LinearRing>
<gml:posList srsDimension="2">-8236070.085302306 4974636.883205217 -8234716.512732034 4974464.899891576 -8234716.512732034 4973573.134464388 -8236391.757990729 4973614.537951903 -8236070.085302306 4974636.883205217</gml:posList>
</gml:LinearRing>
</gml:exterior>
</gml:Polygon>
</Within>
</ogc:Filter>
</wfs:Query>
</wfs:GetFeature>
```
![image47126](./images/image47126.png)
#### 3.4 Transaction
1. Insert
```xml
<?xml version="1.0"?>
<wfs:Transaction
version="1.1.0"
service="WFS"
xmlns="http://www.someserver.com/myns"
xmlns:gml="http://www.opengis.net/gml"
xmlns:ogc="http://www.opengis.net/ogc"
xmlns:test="http://localhost:8080/test"
xmlns:wfs="http://www.opengis.net/wfs"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://www.someserver.com/myns
http://www.someserver.com/wfs/cwwfs.cgi?
http://www.opengis.net/wfs ../wfs/1.1.0/WFS.xsd">
<wfs:Insert inputFormat="text/xml;subtype=2.1.2" idgen="UseExisting">
<test:tiger_roads gml:id="10002">
<cfcc>A94</cfcc>
<name>测试</name>
<geom>
<MultiLineString srsName="EPSG:3857">
<lineStringMember>
<LineString>
<coordinates>-8237795.685217111,4980323.905513588 -8238827.585098961,4978584.963120101</coordinates>
</LineString>
</lineStringMember>
</MultiLineString>
</geom>
</test:tiger_roads>
</wfs:Insert>
</wfs:Transaction>
```
2. update
```xml
<?xml version="1.0"?>
<wfs:Transaction
version="1.1.0"
service="WFS"
xmlns="http://www.someserver.com/myns"
xmlns:gml="http://www.opengis.net/gml"
xmlns:ogc="http://www.opengis.net/ogc"
xmlns:test="http://localhost:8080/test"
xmlns:wfs="http://www.opengis.net/wfs"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://www.someserver.com/myns
http://www.someserver.com/wfs/cwwfs.cgi?
http://www.opengis.net/wfs ../wfs/1.1.0/WFS.xsd">
<wfs:Update typeName="tiger_roads">
<wfs:Property>
<wfs:Name>name</wfs:Name>
<wfs:Value>测试Insert312</wfs:Value>
</wfs:Property>
<ogc:Filter>
<ogc:GmlObjectId gml:id="tiger_roads.8338"/>
</ogc:Filter>
</wfs:Update>
</wfs:Transaction>
```
3. delete
```xml
<?xml version="1.0" ?>
<wfs:Transaction
version="1.1.0"
service="WFS"
xmlns="http://www.someserver.com/myns"
xmlns:ogc="http://www.opengis.net/ogc"
xmlns:wfs="http://www.opengis.net/wfs"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://www.opengis.net/wfs ../wfs/1.1.0/WFS.xsd">
<wfs:Delete typeName="tiger_roads">
<ogc:Filter>
<ogc:GmlObjectId gml:id="tiger_roads.8337"/>
</ogc:Filter>
</wfs:Delete>
</wfs:Transaction>
```
### 参考文章
[1] [WFS Reference](https://docs.geoserver.org/latest/en/user/services/wfs/reference.html) :`https://docs.geoserver.org/latest/en/user/services/wfs/reference.html`
[2] [Filter Reference](https://docs.geoserver.org/2.12.2/user/filter/filter_reference.html) :`https://docs.geoserver.org/2.12.2/user/filter/filter_reference.html`
[3] [Filter Encoding](https://www.ogc.org/standards/filter) :`https://www.ogc.org/standards/filter`