Solved

GML geometry to WKT geometry


Badge +7

I have an attribute that contains GML geometry that I would like to convert to WKT geometry but its not going so well. For the easy geometry in these files a simple GeometryReplacer does the trick and with a simple stringsplit action in python this is also converted without using too much resources. 

<?xml version="1.0" encoding="UTF-16"?>
<stufgeo:kruinlijnBegroeidTerreindeel xmlns:stufgeo="http://www.geostandaarden.nl/imgeo/2.1/stuf-imgeo/1.3">
    <gml:Curve srsName="EPSG:28992" xmlns:gml="http://www.opengis.net/gml">
     <gml:segments>
      <gml:LineStringSegment>
       <gml:posList srsDimension="2">161274.467 453784.372 161277.253 453785.924 161279.958 453787.131 161280.921 453787.508</gml:posList>
      </gml:LineStringSegment>
     </gml:segments>
    </gml:Curve>
   </stufgeo:kruinlijnBegroeidTerreindeel>

Using stringsplit or Python the result would look like this:

LINESTRING(161274.467 453784.372,161277.253 453785.924,161279.958 453787.131,161280.921 453787.508)

But i have problems getting the results of these mixed GML's 

<?xml version="1.0" encoding="UTF-16"?>
<imgeo:kruinlijnOndersteunendWegdeel xmlns:imgeo="http://www.geostandaarden.nl/imgeo/2.1/stuf-imgeo/1.3">
<Curve srsName="urn:ogc:def:crs:EPSG::28992" xmlns="http://www.opengis.net/gml">
<segments>
<LineStringSegment>
<posList srsDimension="2">168343.153 449846.404 168341.911 449843.424 168340.901 449841.832</posList>
</LineStringSegment>
<Arc>
<posList srsDimension="2">168340.901 449841.832 168335.828 449829.203 168330.801 449816.556</posList>
</Arc>
<LineStringSegment>
<posList srsDimension="2">168330.801 449816.556 168323.346 449795.591 168322.728 449793.771</posList>
</LineStringSegment>
<Arc>
<posList srsDimension="2">168322.728 449793.771 168318.423 449780.815 168314.308 449767.798</posList>
</Arc>
<Arc>
<posList srsDimension="2">168314.308 449767.798 168310.486 449755.177 168306.851 449742.500</posList>
</Arc>
<Arc>
<posList srsDimension="2">168306.851 449742.500 168304.954 449735.475 168303.402 449728.365</posList>
</Arc>
<Arc>
<posList srsDimension="2">168303.402 449728.365 168303.202 449727.504 168303.045 449726.635</posList>
</Arc>
</segments>
</Curve>
</imgeo:kruinlijnOndersteunendWegdeel>

Is there a way in FME to convert these to WKT directly before i need to think about using the PythonCaller here? The GeometryReplacer does not work for this example.

icon

Best answer by takashi 19 April 2018, 16:37

View original

16 replies

Userlevel 5
Badge +25

What I usually do is read it as XML, then feed the entire xml_fragment into a GeometryReplacer (set to GML as geometry type). Once that has built the geometry you should be able to use a GeometryExtractor to get it back to WKT.

I tried that with your sample and noticed that in WKT the arcs are replaced with linestrings though, so instead of building a 7-part geometry it's a single line. I'm pretty sure that's not what you want. I seem to recall a recent support case where FME handled different kinds of GML arcs in different ways, wonder if that's popping up here too... @TiaAtSafe helped me with that one (C133450)

Userlevel 4

The easiest is probably to first convert the GML to a regular FME geometry, then convert to WKT using the GeometryExtractor.

The GeometryReplacer works fine if you only send the <Curve> tags, you can use an XMLQueryExtractor with the following XQuery expression:

/*/*

Then send the result to the GeometryReplacer set to "GML". You may want to consider using the ArcStroker before converting to WKT.

Badge +7

Thanks, for the lines this works well but, as you said, the arc's do not work correctly

If arc is first this will be the result:

<?xml version="1.0" encoding="UTF-16"?><imgeo:kruinlijnOndersteunendWegdeel xmlns:imgeo="http://www.geostandaarden.nl/imgeo/2.1/stuf-imgeo/1.3">
<Curve srsName="urn:ogc:def:crs:EPSG::28992" xmlns="http://www.opengis.net/gml">
<segments>
<Arc>
<posList srsDimension="2">189254.476 431090.159 189254.986 431092.715 189255.406 431095.286</posList>
</Arc>
</segments>
</Curve>
</imgeo:kruinlijnOndersteunendWegdeel>

Is transformed into:

POINT (189181.75710323136 431105.99751930835)

instead of :

CIRCULARSTRING(189254.476 431090.159,189254.986 431092.715,189255.406 431095.286)

0684Q00000ArLokQAF.png

Same if line is first and then the curve. Cruves just dont work like i would expect

For a mix starting with a line and than a curve i would expect somthing like this in WKT:

COMPOUNDCURVE((160888.904
445450.594,160888.999 445450.71,160888.334 445451.253,160882.813
445455.057),CIRCULARSTRING(160882.813 445455.057,160881.86 445455.715,160880.916
445456.387))

0684Q00000ArLwxQAF.png

Badge +7

The easiest is probably to first convert the GML to a regular FME geometry, then convert to WKT using the GeometryExtractor.

The GeometryReplacer works fine if you only send the <Curve> tags, you can use an XMLQueryExtractor with the following XQuery expression:

/*/*

Then send the result to the GeometryReplacer set to "GML". You may want to consider using the ArcStroker before converting to WKT.

 

Thanks, this got things going at least. but the extractor does not give the right results, or atleast not i would expect.
Userlevel 2
Badge +17

Hi @JeroenR, FME doesn't seem to support converting an Arc geometry to the OGC WKT 'CIRCULARSTRING' representation. If it's allowed to transform arcs to approximate line strings, you can use the ArcStroker, as @david_r mentioned before.
Otherwise, I think you will have to implement the conversion from GML to OGC WKT.

My ultimate weapon - XQuery: If the input GML fragment is always "Curve" consisting of "Arc" or "LineStringSegment", the XMLXQueryExtractor with this XQuery expression directly converts the GML to OGC WKT.

declare default element namespace "http://www.opengis.net/gml";
let $t := {
    for $segment in //Curve/segments/*
    let $coords := fn:string-join({
        let $c := fn:tokenize($segment/posList/text(), ' ')
        for $i in (1 to fn:count($c)) where $i mod 2 eq 1
        return $c[$i]||' '||$c[$i + 1]
    }, ',')
    return if (fn:name($segment) eq 'Arc')
        then 'CIRCULARSTRING('||$coords||')'
        else '('||$coords||')'
}
return 'COMPOUNDCURVE('||fn:string-join($t, ',')||')'

0684Q00000ArLjmQAF.png

Userlevel 4

Hi @JeroenR, FME doesn't seem to support converting an Arc geometry to the OGC WKT 'CIRCULARSTRING' representation. If it's allowed to transform arcs to approximate line strings, you can use the ArcStroker, as @david_r mentioned before.
Otherwise, I think you will have to implement the conversion from GML to OGC WKT.

My ultimate weapon - XQuery: If the input GML fragment is always "Curve" consisting of "Arc" or "LineStringSegment", the XMLXQueryExtractor with this XQuery expression directly converts the GML to OGC WKT.

declare default element namespace "http://www.opengis.net/gml";
let $t := {
    for $segment in //Curve/segments/*
    let $coords := fn:string-join({
        let $c := fn:tokenize($segment/posList/text(), ' ')
        for $i in (1 to fn:count($c)) where $i mod 2 eq 1
        return $c[$i]||' '||$c[$i + 1]
    }, ',')
    return if (fn:name($segment) eq 'Arc')
        then 'CIRCULARSTRING('||$coords||')'
        else '('||$coords||')'
}
return 'COMPOUNDCURVE('||fn:string-join($t, ',')||')'

0684Q00000ArLjmQAF.png

Nice! That's some black-belt XQuery!
Badge +7

Hi @JeroenR, FME doesn't seem to support converting an Arc geometry to the OGC WKT 'CIRCULARSTRING' representation. If it's allowed to transform arcs to approximate line strings, you can use the ArcStroker, as @david_r mentioned before.
Otherwise, I think you will have to implement the conversion from GML to OGC WKT.

My ultimate weapon - XQuery: If the input GML fragment is always "Curve" consisting of "Arc" or "LineStringSegment", the XMLXQueryExtractor with this XQuery expression directly converts the GML to OGC WKT.

declare default element namespace "http://www.opengis.net/gml";
let $t := {
    for $segment in //Curve/segments/*
    let $coords := fn:string-join({
        let $c := fn:tokenize($segment/posList/text(), ' ')
        for $i in (1 to fn:count($c)) where $i mod 2 eq 1
        return $c[$i]||' '||$c[$i + 1]
    }, ',')
    return if (fn:name($segment) eq 'Arc')
        then 'CIRCULARSTRING('||$coords||')'
        else '('||$coords||')'
}
return 'COMPOUNDCURVE('||fn:string-join($t, ',')||')'

0684Q00000ArLjmQAF.png

 

This looks like the solution.I did not get it working for my single LineStringSegment gml but will try to edit it so it will work if there is only a single LineStringSegment in the GML.My working day is over so will keep you posted here :) Thanks!
Badge +7

Hi @JeroenR, FME doesn't seem to support converting an Arc geometry to the OGC WKT 'CIRCULARSTRING' representation. If it's allowed to transform arcs to approximate line strings, you can use the ArcStroker, as @david_r mentioned before.
Otherwise, I think you will have to implement the conversion from GML to OGC WKT.

My ultimate weapon - XQuery: If the input GML fragment is always "Curve" consisting of "Arc" or "LineStringSegment", the XMLXQueryExtractor with this XQuery expression directly converts the GML to OGC WKT.

declare default element namespace "http://www.opengis.net/gml";
let $t := {
    for $segment in //Curve/segments/*
    let $coords := fn:string-join({
        let $c := fn:tokenize($segment/posList/text(), ' ')
        for $i in (1 to fn:count($c)) where $i mod 2 eq 1
        return $c[$i]||' '||$c[$i + 1]
    }, ',')
    return if (fn:name($segment) eq 'Arc')
        then 'CIRCULARSTRING('||$coords||')'
        else '('||$coords||')'
}
return 'COMPOUNDCURVE('||fn:string-join($t, ',')||')'

0684Q00000ArLjmQAF.png

Not really a star in xQuery.

 


 


Is it possible to add something like: 

 


 

declare default element namespace "http://www.opengis.net/gml";
let $t := {
for $segment in //Curve/segments/*
let $coords := fn:string-join({
let $c := fn:tokenize($segment/posList/text(), ' ')
for $i in (1 to fn:count($c)) where $i mod 2 eq 1
return $c[$i]||' '||$c[$i + 1]

If count(total_amount_of_objects_in_segments) = 1:
  if (fn:name($segment) eq 'Arc' or 'gml:Arc')
    then return 'CIRCULARSTRING('||$coords||')'
elif (fn:name($segment) eq 'LineStringSegment' or 'gml:LineStringSegment')
then return 'LINESTRING('||$coords||')'
else error
else  if count(total_amount_of_objects_in_segments) > 1:
Your compound script that makes compound curves.
Badge +7

Edit: The code elow does not work.

geotest.fmw

It looks like this works, but is it really correct?

Somehow the 

    else if (fn:name($segment) != 'LineStringSegment')        then 'LINESTRING('||$coords||')'        else '('||$coords||')'

does not feel right but it gives the correct results in my test workflow.

declare default element namespace "http://www.opengis.net/gml";let $t := {    for $segment in //Curve/segments/*    let $coords := fn:string-join({        let $c := fn:tokenize($segment/posList/text(), ' ')        for $i in (1 to fn:count($c)) where $i mod 2 eq 1        return $c[$i]||' '||$c[$i + 1]    }, ',')    return if (fn:name($segment) eq 'Arc')        then 'CIRCULARSTRING('||$coords||')'    else if (fn:name($segment) != 'LineStringSegment')        then 'LINESTRING('||$coords||')'        else '('||$coords||')'}return if (fn:starts-with(fn:string-join($t, ','), 'LINESTRING') eq true)     then $t    else 'COMPOUNDCURVE('||fn:string-join($t, ',')||')'
Userlevel 2
Badge +17

Hi @JeroenR, FME doesn't seem to support converting an Arc geometry to the OGC WKT 'CIRCULARSTRING' representation. If it's allowed to transform arcs to approximate line strings, you can use the ArcStroker, as @david_r mentioned before.
Otherwise, I think you will have to implement the conversion from GML to OGC WKT.

My ultimate weapon - XQuery: If the input GML fragment is always "Curve" consisting of "Arc" or "LineStringSegment", the XMLXQueryExtractor with this XQuery expression directly converts the GML to OGC WKT.

declare default element namespace "http://www.opengis.net/gml";
let $t := {
    for $segment in //Curve/segments/*
    let $coords := fn:string-join({
        let $c := fn:tokenize($segment/posList/text(), ' ')
        for $i in (1 to fn:count($c)) where $i mod 2 eq 1
        return $c[$i]||' '||$c[$i + 1]
    }, ',')
    return if (fn:name($segment) eq 'Arc')
        then 'CIRCULARSTRING('||$coords||')'
        else '('||$coords||')'
}
return 'COMPOUNDCURVE('||fn:string-join($t, ',')||')'

0684Q00000ArLjmQAF.png

Need to clarify the conditions and requirements.

 

Conditions:

 

  • The GML geometry representation is always a "Curve" element which contains a single "segments" element.
  • The "segments" element can contain one or more "LineStringSegment" or "Arc" element.
Requirements: I'm unclear the 4th requirement below.

 

  1. If the "segments" consists of just a single "Arc" element, it should be converted to "CIRCULARSTRING".
  2. If the "segments" consists of just a single "LineStringSegment" element, it should be converted to "LINESTRING".
  3. If the "segments" consists of two or more children and one or more of them is "Arc", it should be converted to "COMPOUNDCURVE" consisting of some "LINESTRING" and some "CIRCULARSTRING".
  4. If the "segment" consists of two or more children and all of them are "LineStringSegment", it should be converted to ?
Badge +7

Edit: The code elow does not work.

geotest.fmw

It looks like this works, but is it really correct?

Somehow the 

    else if (fn:name($segment) != 'LineStringSegment')        then 'LINESTRING('||$coords||')'        else '('||$coords||')'

does not feel right but it gives the correct results in my test workflow.

declare default element namespace "http://www.opengis.net/gml";let $t := {    for $segment in //Curve/segments/*    let $coords := fn:string-join({        let $c := fn:tokenize($segment/posList/text(), ' ')        for $i in (1 to fn:count($c)) where $i mod 2 eq 1        return $c[$i]||' '||$c[$i + 1]    }, ',')    return if (fn:name($segment) eq 'Arc')        then 'CIRCULARSTRING('||$coords||')'    else if (fn:name($segment) != 'LineStringSegment')        then 'LINESTRING('||$coords||')'        else '('||$coords||')'}return if (fn:starts-with(fn:string-join($t, ','), 'LINESTRING') eq true)     then $t    else 'COMPOUNDCURVE('||fn:string-join($t, ',')||')'
:( it only works because the variable segment is named gml:LineStringSegment and LineStringSegment. If both are the same the above does nog work at all. 

 

 

Badge +7
Need to clarify the conditions and requirements.

 

Conditions:

 

  • The GML geometry representation is always a "Curve" element which contains a single "segments" element.
  • The "segments" element can contain one or more "LineStringSegment" or "Arc" element.
Requirements: I'm unclear the 4th requirement below.

 

  1. If the "segments" consists of just a single "Arc" element, it should be converted to "CIRCULARSTRING".
  2. If the "segments" consists of just a single "LineStringSegment" element, it should be converted to "LINESTRING".
  3. If the "segments" consists of two or more children and one or more of them is "Arc", it should be converted to "COMPOUNDCURVE" consisting of some "LINESTRING" and some "CIRCULARSTRING".
  4. If the "segment" consists of two or more children and all of them are "LineStringSegment", it should be converted to ?
I updated the dummycode above:

 

 

Conditions:

 

 

  • Yes GML geometry representation is always a "Curve" element with a single Segment
  • The "segments" element can contain one or more "LineStringSegment" or "Arc" element but cannot contain more than one LineStringSegments if there are no arc's.
  • If the "segments" consists of just a single "LineStringSegment" element it should be a "LINESTRING".Multiple LineStingSegments without any Arc's should not be in the data.
  • Arc should always be converted to "CIRCULARSTRING" but if there is only 1 Arc it should not become a COMPOUNDCURVE .
  • Yes, the "segments" who consists of two or more children and one or more of them is "Arc", it should be converted to "COMPOUNDCURVE" consisting of lines (withou LINESTRING: '('||$coords||')') and some "CIRCULARSTRING".
Userlevel 2
Badge +17

Hi @JeroenR, FME doesn't seem to support converting an Arc geometry to the OGC WKT 'CIRCULARSTRING' representation. If it's allowed to transform arcs to approximate line strings, you can use the ArcStroker, as @david_r mentioned before.
Otherwise, I think you will have to implement the conversion from GML to OGC WKT.

My ultimate weapon - XQuery: If the input GML fragment is always "Curve" consisting of "Arc" or "LineStringSegment", the XMLXQueryExtractor with this XQuery expression directly converts the GML to OGC WKT.

declare default element namespace "http://www.opengis.net/gml";
let $t := {
    for $segment in //Curve/segments/*
    let $coords := fn:string-join({
        let $c := fn:tokenize($segment/posList/text(), ' ')
        for $i in (1 to fn:count($c)) where $i mod 2 eq 1
        return $c[$i]||' '||$c[$i + 1]
    }, ',')
    return if (fn:name($segment) eq 'Arc')
        then 'CIRCULARSTRING('||$coords||')'
        else '('||$coords||')'
}
return 'COMPOUNDCURVE('||fn:string-join($t, ',')||')'

0684Q00000ArLjmQAF.png

This expression may be close to your requirement. This expression returns empty string when the input didn't match any condition. The "fn:local-name" function returns the node name except namespace qualifier.

 

declare default element namespace "http://www.opengis.net/gml";
declare function local:coords($p as element(posList)) as xs:string
{
    fn:string-join({
        let $c := fn:tokenize($p/text(), '\s+')
        for $i in (1 to fn:count($c)) where $i mod 2 eq 1
        return $c[$i]||' '||$c[$i + 1] 
    }, ',')
};
let $segments := //Curve/segments/*
return if (fn:count($segments) eq 1)
    then {
        if (fn:local-name($segments[1]) eq 'Arc')
            then 'CIRCULARSTRING('|| local:coords($segments[1]/posList) ||')'
        else if (fn:local-name($segments[1]) eq 'LineStringSegment')
            then 'LINESTRING('|| local:coords($segments[1]/posList) ||')'
        else ()
    }
    else if (1 < fn:count($segments))
    then {
        let $parts := {
            for $s in $segments
            let $coords := local:coords($s/posList)
            return if (fn:local-name($s) eq 'Arc')
                then 'CIRCULARSTRING('|| $coords ||')'
                else '('|| $coords ||')'
        }
        return 'COMPOUNDCURVE('|| fn:string-join($parts, ',') ||')'
    }
    else ()

 

Badge +7
This expression may be close to your requirement. This expression returns empty string when the input didn't match any condition. The "fn:local-name" function returns the node name except namespace qualifier.

 

declare default element namespace "http://www.opengis.net/gml";
declare function local:coords($p as element(posList)) as xs:string
{
    fn:string-join({
        let $c := fn:tokenize($p/text(), '\s+')
        for $i in (1 to fn:count($c)) where $i mod 2 eq 1
        return $c[$i]||' '||$c[$i + 1] 
    }, ',')
};
let $segments := //Curve/segments/*
return if (fn:count($segments) eq 1)
    then {
        if (fn:local-name($segments[1]) eq 'Arc')
            then 'CIRCULARSTRING('|| local:coords($segments[1]/posList) ||')'
        else if (fn:local-name($segments[1]) eq 'LineStringSegment')
            then 'LINESTRING('|| local:coords($segments[1]/posList) ||')'
        else ()
    }
    else if (1 < fn:count($segments))
    then {
        let $parts := {
            for $s in $segments
            let $coords := local:coords($s/posList)
            return if (fn:local-name($s) eq 'Arc')
                then 'CIRCULARSTRING('|| $coords ||')'
                else '('|| $coords ||')'
        }
        return 'COMPOUNDCURVE('|| fn:string-join($parts, ',') ||')'
    }
    else ()

 

@takashi 

 

 

I have a question about your code and how to convert it to accept polygons? Using your script it generates a line from the outer line that can be transformed to a polygon by just adding CURVEPOLYGON() to the string. Would it be possible to loop the part below "let $segments := //Curve/segments/*" with the same same option as like in the curves?

 

 

This is an example for an polygon that only got the exterior layer: 

 

 

CURVEPOLYGON(COMPOUNDCURVE((144734.339 478871.234,144726.116 478866.683,144721.989 478874.296,144730.113 478878.77,144734.371 478881.114,144734.303 478881.189,144734.164 478881.289),CIRCULARSTRING(144734.164 478881.289,144731.421 478882.294,144728.561 478882.886),CIRCULARSTRING(144728.561 478882.886,144727.633 478883.047,144726.698 478883.158),CIRCULARSTRING(144726.698 478883.158,144725.069 478883.233,144723.44 478883.159),(144723.44 478883.159,144721.185 478882.943,144714.355 478879.602,144682.01 478863.689),CIRCULARSTRING(144682.01 478863.689,144680.652 478862.715,144679.681 478861.354),CIRCULARSTRING(144679.681 478861.354,144678.672 478858.547,144678.584 478855.565),CIRCULARSTRING(144678.584 478855.565,144679.407 478852.683,144680.715 478849.987),(144680.715 478849.987,144681.996 478848.051,144684.391 478845.04,144686.158 478842.817,144687.119 478841.754,144688.152 478840.611,144690.832 478837.647,144702.259 478824.291,144703.152 478823.248,144707.042 478818.762),CIRCULARSTRING(144707.042 478818.762,144709.288 478816.375,144711.726 478814.184),(144711.726 478814.184,144717.306 478809.181,144719.539 478810.783,144719.833 478810.039,144723.115 478811.253,144723.233 478810.934,144732.692 478814.492,144744.69 478819.005,144747.047 478812.905,144743.754 478811.663,144743.578 478812.131,144742.614 478811.769,144742.93 478810.927,144735.259 478808.049,144725.687 478804.457,144724.014 478808.571,144719.732 478807.033,144719.974 478806.805,144720.358 478806.488),CIRCULARSTRING(144720.358 478806.488,144725.31 478803.273,144730.74 478800.957),CIRCULARSTRING(144730.74 478800.957,144735.978 478800.133,144741.267 478800.513),(144741.267 478800.513,144743.047 478801.18,144748.647 478804.123,144749.028 478804.365,144751.113 478806.607,144751.409 478806.906,144751.377 478807.029,144756.296 478812.026,144756.98 478812.785,144762.456 478818.126,144771.628 478827.332,144775.854 478831.56,144775.483 478835.895,144768.396 478843.718,144764.279 478848.203,144760.712 478852.28,144751.004 478862.771,144742.884 478871.68,144740.438 478870.348,144738.654 478873.622,144734.339 478871.234)))

 

Badge +7
@takashi 

 

 

I have a question about your code and how to convert it to accept polygons? Using your script it generates a line from the outer line that can be transformed to a polygon by just adding CURVEPOLYGON() to the string. Would it be possible to loop the part below "let $segments := //Curve/segments/*" with the same same option as like in the curves?

 

 

This is an example for an polygon that only got the exterior layer: 

 

 

CURVEPOLYGON(COMPOUNDCURVE((144734.339 478871.234,144726.116 478866.683,144721.989 478874.296,144730.113 478878.77,144734.371 478881.114,144734.303 478881.189,144734.164 478881.289),CIRCULARSTRING(144734.164 478881.289,144731.421 478882.294,144728.561 478882.886),CIRCULARSTRING(144728.561 478882.886,144727.633 478883.047,144726.698 478883.158),CIRCULARSTRING(144726.698 478883.158,144725.069 478883.233,144723.44 478883.159),(144723.44 478883.159,144721.185 478882.943,144714.355 478879.602,144682.01 478863.689),CIRCULARSTRING(144682.01 478863.689,144680.652 478862.715,144679.681 478861.354),CIRCULARSTRING(144679.681 478861.354,144678.672 478858.547,144678.584 478855.565),CIRCULARSTRING(144678.584 478855.565,144679.407 478852.683,144680.715 478849.987),(144680.715 478849.987,144681.996 478848.051,144684.391 478845.04,144686.158 478842.817,144687.119 478841.754,144688.152 478840.611,144690.832 478837.647,144702.259 478824.291,144703.152 478823.248,144707.042 478818.762),CIRCULARSTRING(144707.042 478818.762,144709.288 478816.375,144711.726 478814.184),(144711.726 478814.184,144717.306 478809.181,144719.539 478810.783,144719.833 478810.039,144723.115 478811.253,144723.233 478810.934,144732.692 478814.492,144744.69 478819.005,144747.047 478812.905,144743.754 478811.663,144743.578 478812.131,144742.614 478811.769,144742.93 478810.927,144735.259 478808.049,144725.687 478804.457,144724.014 478808.571,144719.732 478807.033,144719.974 478806.805,144720.358 478806.488),CIRCULARSTRING(144720.358 478806.488,144725.31 478803.273,144730.74 478800.957),CIRCULARSTRING(144730.74 478800.957,144735.978 478800.133,144741.267 478800.513),(144741.267 478800.513,144743.047 478801.18,144748.647 478804.123,144749.028 478804.365,144751.113 478806.607,144751.409 478806.906,144751.377 478807.029,144756.296 478812.026,144756.98 478812.785,144762.456 478818.126,144771.628 478827.332,144775.854 478831.56,144775.483 478835.895,144768.396 478843.718,144764.279 478848.203,144760.712 478852.28,144751.004 478862.771,144742.884 478871.68,144740.438 478870.348,144738.654 478873.622,144734.339 478871.234)))

 

And the source of the above 

 

gml-met-curves-en-interior-geo-zonder-cruves.txt

 

Userlevel 2
Badge +17

Hi @JeroenR, FME doesn't seem to support converting an Arc geometry to the OGC WKT 'CIRCULARSTRING' representation. If it's allowed to transform arcs to approximate line strings, you can use the ArcStroker, as @david_r mentioned before.
Otherwise, I think you will have to implement the conversion from GML to OGC WKT.

My ultimate weapon - XQuery: If the input GML fragment is always "Curve" consisting of "Arc" or "LineStringSegment", the XMLXQueryExtractor with this XQuery expression directly converts the GML to OGC WKT.

declare default element namespace "http://www.opengis.net/gml";
let $t := {
    for $segment in //Curve/segments/*
    let $coords := fn:string-join({
        let $c := fn:tokenize($segment/posList/text(), ' ')
        for $i in (1 to fn:count($c)) where $i mod 2 eq 1
        return $c[$i]||' '||$c[$i + 1]
    }, ',')
    return if (fn:name($segment) eq 'Arc')
        then 'CIRCULARSTRING('||$coords||')'
        else '('||$coords||')'
}
return 'COMPOUNDCURVE('||fn:string-join($t, ',')||')'

0684Q00000ArLjmQAF.png

Reuse the previous code maximal. Hope this works fine.

 

declare default element namespace "http://www.opengis.net/gml/";
declare function local:coords($p as element(posList)) as xs:string
{
    fn:string-join({
        let $c := fn:tokenize($p/text(), '\s+')
        for $i in (1 to fn:count($c)) where $i mod 2 eq 1
        return $c[$i]||' '||$c[$i + 1] 
    }, ',')
};

declare function local:ring-to-ogc-wkt-curve($r as element(Ring)) as xs:string
{
    let $segments := $r//Curve/segments/*
    return if (fn:count($segments) eq 1)
        then {
            if (fn:local-name($segments[1]) eq 'Arc')
                then 'CIRCULARSTRING('|| local:coords($segments[1]/posList) ||')'
            else if (fn:local-name($segments[1]) eq 'LineStringSegment')
                then 'LINESTRING('|| local:coords($segments[1]/posList) ||')'
            else ()
        }
        else if (1 < fn:count($segments))
        then {
            let $parts := {
                for $s in $segments
                let $coords := local:coords($s/posList)
                return if (fn:local-name($s) eq 'Arc')
                    then 'CIRCULARSTRING('|| $coords ||')'
                    else '('|| $coords ||')'
            }
            return 'COMPOUNDCURVE('|| fn:string-join($parts, ',') ||')'
        }
        else ()    
};

for $p in //PolygonPatch
return 'CURVEPOLYGON(' || fn:string-join({
    for $r in $p/*[self::exterior or self::interior]/*
    return
        if (fn:local-name($r) eq 'Ring')
            then local:ring-to-ogc-wkt-curve($r)  
        else if (fn:local-name($r) eq 'LinearRing') 
            then 'LINESTRING('|| local:coords($r/posList) ||')'
        else ()
}, ',') || ')'

Reply