Hi,

That was the one documentation I was missing.
I do want to make a function that extracts this information, rather than a 
xpath accessor. It would've been nice if that function wasn't too verbose. I 
will look more into your examples and see how it can be done.

I'm pretty sure there is some bugs there, so I will make some tickets for 
those. Maybe I will do something about the documentation as well.

Thanks for your time, Jody.

Regards,

Roar Brænden


> 1. sep. 2021 kl. 00:21 skrev Jody Garnett <jody.garn...@gmail.com>:
> 
> Sorry I do not have more time for this, there are a couple spots which seem 
> really odd to me in your example.
> 
> (Collection<Property>) nextFeature.getProperty("kommunenavn").getValue()
> 
> I was trying to sort out why this was a collection - it does not match any of 
> the examples in the javadocs here 
> (https://docs.geotools.org/latest/javadocs/org/opengis/feature/ComplexAttribute.html
>  
> <https://docs.geotools.org/latest/javadocs/org/opengis/feature/ComplexAttribute.html>).
> 
> Do you have the feature model information (descriptors and types if you are 
> building by hand, or the XSD if you are building from an XML Schema). I find 
> I am making too many guesses without a guide :D
> 
> It also looks like you are working very hard to query information out of your 
> data structure; a property accessor should be able to help.
> 
> PropertyName xpath = factory.property( "foo/bar" );
>    Property bar = xpath.evaluate( attribute );
> 
> It is known that GML is very verbose, with many of the examples repeating 
> information. It took me a while to see the naming convention identifikasjon 
> vs Identifikasjon. I do not know why there is not a single identifikasjon 
> with multiplicity 1..N ? Is that a decision the application schema author 
> made?
> 
> 
> --
> Jody Garnett
> 
> 
> On Tue, 31 Aug 2021 at 13:46, Roar Brænden <roar.brenden...@gmail.com 
> <mailto:roar.brenden...@gmail.com>> wrote:
> 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 
>> <mailto: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