XLinkProperties
Discussion page for finding the most suitable approach for implementing XLink-properties/referenced objects in the deegree3 object model.
1. XLink properties in GML documents
Example 1: Two features with one feature referencing the other
<House gml:id="H1">
...
<room xlink:href="#K1"/>
...
</House>
<Kitchen gml:id="K1">
...
</Kitchen>
Example 2: Two features that reference each other
<House gml:id="H1">
...
<room xlink:href="#K1"/>
...
</House>
<Kitchen gml:id="K1">
...
<belongsTo xlink:href="#H1"/>
...
</Kitchen>
Example 3: MultiGeometry with a LineString member that references a Point object
<MultiGeometry ..>
<geometryMembers>
<Point gml:id="P1">
<coord>
<X>0.0</X>
<Y>0.0</Y>
</coord>
</Point>
<Point gml:id="P2">
<coord>
<X>1.0</X>
<Y>1.0</Y>
</coord>
</Point>
<LineString gml:id="L1">
<pointProperty xlink:href="#P1" />
<pointProperty>
<Point>
<pos>1.0 0.0</pos>
</Point>
</pointProperty>
<pointProperty xlink:href="#P2" />
<pointProperty>
<Point>
<pos>0.0 1.0</pos>
</Point>
</pointProperty>
</LineString>
</geometryMembers>
</MultiGeometry>
Example 4: A Feature referencing remote objects using GetGmlObject
<app:Philosopher gml:id="PHILOSOPHER_1">
<app:id>1</app:id>
<app:name>Karl Marx</app:name>
...
<app:dateOfBirth>1818-05-05</app:dateOfBirth>
<app:placeOfBirth
xlink:href="http://demo.deegree.org/deegree-wfs/services?SERVICE=WFS&VERSION=1.1.0&REQUEST=GetGmlObject&TRAVERSEXLINKDEPTH=1&GMLOBJECTID=PLACE_714"/>
<app:dateOfDeath>1883-03-14</app:dateOfDeath>
<app:placeOfDeath
xlink:href="http://demo.deegree.org/deegree-wfs/services?SERVICE=WFS&VERSION=1.1.0&REQUEST=GetGmlObject&TRAVERSEXLINKDEPTH=1&GMLOBJECTID=PLACE_716"/>
</app:Philosopher>
2. General observations
- XLink references in GML documents may be local (i.e. they point to an object in the same document) or remote (i.e. they reference an object using an URL).
Features properties may reference both Geometry and Feature objects (and others as well, e.g. CoordinateSystems, but that's out of the scope for now).
- If xlinks are used, the resulting feature structure may be cyclic (see Example 2).
Some types of geometries are built upon other geometry objects, e.g. LineStrings (built from Points) or MultiGeometries (built from arbitrary Geometries). The constituting geometry objects may be specified as references in a GML representation (local or remote).
- Local xlinks should probably be resolved after parsing, so a GML document so the resulting feature/geometry network contains only Java references and may be traversed easily.
- Remote xlinks should probably not be resolved automatically as remote references may be temporarily unavailable and the nested structure may be arbitrary large (it may
contain remote xlinks to other objects as well).
3. Implementation options
3.1. Referenced feature values
The following simple Feature wrapper class is used to represent xlink-references (local as well as remote) encountered during the parsing of GML documents:
public class FeatureReference implements Feature {
private String href;
private String fid;
private Feature feature;
private FeatureType ft;
public FeatureReference (String href) {
this.href = href;
int pos = href.lastIndexOf( '#' );
if (pos < 0) {
String msg = "Reference string (='" + href + "') does not contain a '#' character.";
throw new IllegalArgumentException(msg);
}
fid = href.substring( pos + 1 );
}
public FeatureReference (String href, FeatureType ft) {
this (href);
this.ft = ft;
}
public void resolve (Feature feature) {
if (this.feature != null) {
String msg = "Internal error: Feature reference (" + href + ") has already been resolved.";
throw new RuntimeException(msg);
}
this.feature = feature;
}
public Envelope getEnvelope() {
return feature.getEnvelope();
}
public Property<Geometry>[] getGeometryProperties() {
return feature.getGeometryProperties();
}
public String getId() {
return fid;
}
public QName getName() {
return feature.getName();
}
public FeatureType getType() {
return ft;
}
public void setId( String id ) {
feature.setId( id );
}
public void setProperties( List<Property<?>> props )
throws IllegalArgumentException {
feature.setProperties( props );
}
public void setPropertyValue( QName propName, int occurence, Object value ) {
feature.setPropertyValue( propName, occurence, value );
}
...
public String getHref() {
return href;
}
}
The parser keeps track of all local FeatureReferences, Features and their ids. After parsing, it's very simple to use this information to resolve the reference objects that target local features (i.e. call #resolve(Feature). To a user of the generated feature objects, it's totally transparent whether feature properties contain Feature objects or local FeatureReferences. For FeatureReference objects that target remote features, it should be possible to write code that fetches these features automatically when the user accesses the FeatureReference.