Hi,

Thanks for the response Jody.

In my original example there was only one kommunenavn, but here I've found one 
with two kommunenavn's:

<app:kommunenavn>
   <app:AdministrativEnhetNavn>
      <app:navn>Hattfjelldal</app:navn>
      <app:språk>nor</app:språk>
   </app:AdministrativEnhetNavn>
   <app:AdministrativEnhetNavn>
      <app:navn>Aarborte</app:navn>
      <app:språk>sma</app:språk>
   </app:AdministrativEnhetNavn>
</app:kommunenavn>


The main goal of my query, is to extract the <app:navn>-element of the 
<app:AdministrativEnhetNavn> where there is an <app:språk>nor</app:språk>.


I've prepared an example at Github 
<https://github.com/roarbra/geotools/blob/d2aea334b6e26d252386db0b594dd1034ee33970/modules/unsupported/wfs-ng/src/test/java/org/geotools/data/wfs/KartverketKommuneReader.java>.
 Here I've taken out the main parts, and written it as I would like it to be:

/* Ordinary feature iterator using getProperty to extract <app:kommunenummer> 
and <app:kommunenavn>. */
/* The content of <app:kommunenavn> must go through findNorskNavn() */
        try (FeatureIterator<Feature> features = 
kommuneSource.getFeatures().features()) {
                while (features.hasNext()) {
                        Feature nextFeature = features.next();
                        String kommunenr = 
(String)nextFeature.getProperty("kommunenummer").getValue();
                        String kommunenavn = 
findNorskNavn((Collection<Property>)nextFeature
                                                                        
.getProperty("kommunenavn")
                                                                        
.getValue());
                                
                        System.out.printf("%s : %s\n", kommunenr, kommunenavn);
                }
        }

/* Loop through all <app:AdministrativEnhetNavn>, return navn with språk=nor. */
        String findNorskNavn(Collection<Property> alleNavn) {
                for (Property inner : alleNavn) {
                        if (matchNorskSprak(inner)) {
                                return extractNavn(inner);
                        }
                }
                return "Without norwegian name.";
        }

/* Return true if <app:AdministrativEnhetNavn> contains a 
<app:språk>nor</app:språk> */
        boolean matchNorskSprak(Property prop) {
                for (Property inner : (Collection<Property>)prop.getValue()) {
                        if ("språk".equals(inner.getName().getLocalPart()) 
                                        && "nor".equals(inner.getValue())) {
                                return true;
                        }
                }
                return false;
        }

/* Return content of <app:navn> within the <app:AdministrativEnhetNavn> */
        String extractNavn(Property prop) {
                for (Property inner : (Collection<Property>)prop.getValue()) {
                        if ("navn".equals(inner.getName().getLocalPart())) {
                                return (String) inner.getValue();
                        }
                }
                throw new RuntimeException("There should've been a \"navn\" 
element.");
        }

Any feedback would be welcome.

Regards,
Roar Brænden



> 31. aug. 2021 kl. 17:35 skrev Jody Garnett <jody.garn...@gmail.com>:
> 
> The use of complex features is mostly confined to the app-schema module, and 
> that is a good source of test cases and examples.
> 
> I helped setup the feature model to enable the app-schema team but did not 
> get a chance to work on it beyond that.  The toString representations are 
> just to aid with debugging, the important asspect is the relationship between 
> the classes to ensure they form a complete descriptive type system.
> 
> Some additional comments inline:
> 
> On Tue, Aug 31, 2021 at 1:21 AM Roar Brænden <roar.brenden...@gmail.com 
> <mailto:roar.brenden...@gmail.com>> wrote:
> I have a WFS source that I try to fetch features from. The response is quite 
> complex, and I've been using org.geotools.data.wfs.impl.WFSDataAccessFactory 
> within gt-wfs-ng.
> 
> I have not tried gt-wfs-ng with complex features myself I am curious how this 
> will go.
> 
> I feel there is something wrong about how this xml are represented as a 
> object graph of Property, but there are so many JUnit tests confirming this 
> structure, so I'm not sure how to make it better. There is also a lack of 
> documentation / examples on how the structure should be.
> 
> The data structure forms a graph of properties; just the same way you could 
> form a data structure using maps and key/value pairs; or layout a java object 
> in memory.  They properties do support some use of user data if you need to 
> hang additional information on the data structuring during processing or 
> parsing etc…
> 
> The type system describes how the layout should be in order to be valid. It 
> is also responsible for defining the meaning of the values with associated 
> description and other “metadata” details.  As a side effect the metadata can 
> also describe default values (useful when setting up a new data), or 
> additional filters (that can be used to validate that the data makes sense).
> 
> The last aspect of the data model is the ability to query values out. In 
> addition to traversing the data structures this was designed for access via 
> xpath (to support WFS xpath property access). 
> 
> I key test of this as a dynamic type system is if the feature type system 
> describes the data structure well enough that you can construct a xpath 
> expression to retrieve the content you wish.
> 
> Here is an example of what the xml looks like:
> 
> <wfs:member>
>     <app:Kommune 
> xmlns:app="http://skjema.geonorge.no/SOSI/produktspesifikasjon/AdmEnheter/4.1 
> <http://skjema.geonorge.no/SOSI/produktspesifikasjon/AdmEnheter/4.1>" 
> gml:id="kommune_view.357">
>       <app:identifikasjon>
>         <app:Identifikasjon>
>           <app:lokalId>173103</app:lokalId>
>           
> <app:navnerom>https://data.geonorge.no/sosi/administrativeenheter/fylker_kommuner</app:navnerom>
>  
> <https://data.geonorge.no/sosi/administrativeenheter/fylker_kommuner%3C/app:navnerom%3E>
>           <app:versjonId>4.1</app:versjonId>
>         </app:Identifikasjon>
>       </app:identifikasjon>
>       <app:oppdateringsdato>2020-02-07T00:00:00</app:oppdateringsdato>
>       <app:datauttaksdato>2021-01-04T10:07:10</app:datauttaksdato>
>       <app:område>
>         <!--Inlined geometry 'kommune_view.357_APP_OMRÅDE'-->
>         <gml:Polygon gml:id="kommune_view.357_APP_OMRÅDE" 
> srsName="urn:ogc:def:crs:EPSG::4258">
>           <gml:exterior>
>             <gml:LinearRing>
>               <gml:posList>58.426581 6.605405 .....</gml:posList>
>             </gml:LinearRing>
>           </gml:exterior>
>         </gml:Polygon>
>       </app:område>
>       <app:kommunenummer>4207</app:kommunenummer>
>       <app:kommunenavn>
>         <app:AdministrativEnhetNavn>
>           <app:navn>Flekkefjord</app:navn>
>           <app:språk>nor</app:språk>
>         </app:AdministrativEnhetNavn>
>       </app:kommunenavn>
>       <app:samiskForvaltningsområde>false</app:samiskForvaltningsområde>
>     </app:Kommune>
>   </wfs:member>
> 
> 
> The <wfs:member><app:Kommune> is the root for a singe Feature. When calling 
> getProperties you will get all the child elements of Kommune represented as a 
> subclass of Property. That contains a name, value and binding. This works 
> great for ordinary values as string, dates, boolean and geometry. The problem 
> is when there's a child element, like for instance <app:kommunenavn>.
> 
> 
> This is represented as a ComplexAttribute and has a Collection as a value. 
> The Collection is actually a Collection of Property's.
> 
> I am confused here, do you mean that more than one kommunenavn is allowed? 
> Like min occurs 0, max occurs N? If so you should get repeated individual 
> properties rather than a single one with a collection value.
> 
> Underneath I've tried to represent this. Ordinary Attribute's are written as: 
> "name [type] : value", while ComplexAttribute's are written "name {" with new 
> indentation for their nested properties:
> 
> samiskForvaltningsområde  [java.lang.Boolean]: false
> IdentifikasjonPropertyType {
>   Identifikasjon {
>     IdentifikasjonType {
>       lokalId  [java.lang.String]: 173103
>       navnerom  [java.lang.String]: https://data.geonorge.no/sosi/ 
> <https://data.geonorge.no/sosi/>
>       versjonId  [java.lang.String]: 4.1
>     }
>   }
> }
> kommunenummer  [java.lang.String]: 4207
> AdministrativEnhetNavnPropertyType {
>   AdministrativEnhetNavn {
>     AdministrativEnhetNavnType {
>       navn  [java.lang.String]: Flekkefjord
>       språk  [java.lang.String]: nor
>     }
>   }
> }
> oppdateringsdato  [java.sql.Timestamp]: 2020-02-07 01:00:00.0
> område  [org.locationtech.jts.geom.Polygon]: POLYGON ((58.426581 6.605405, 
> datauttaksdato  [java.sql.Timestamp]: 2021-01-04 11:07:10.0
> 
> If you have suggestions for the toStirng representations we welcome pull 
> requests; they are mostly used to aid in debugging. With GML and JSON used 
> between systems.
> 
> I would like "IdentifikasjonPropertyType" to have the name "identifikasjon", 
> and the property IdentifikasjonType is superfluous.
> 
> I do not understand, the property is the only real thing (ie data structure). 
> The property type describes how it operates.
> 
> Do anyone have an idea why it's done like it is today, or do anyone have an 
> opinion about my changes? It would be nice to hear about them.
> 
> Thanks for this discussion I hope we can sort out how to accomplish what you 
> wish. 
> 
> Jody
> -- 
> --
> Jody Garnett

_______________________________________________
GeoTools-Devel mailing list
GeoTools-Devel@lists.sourceforge.net
https://lists.sourceforge.net/lists/listinfo/geotools-devel

Reply via email to