Skip to main content

Hi, I have an XML-File which I read with flattening. Part of the XML structure is something like:

<element>
   <points>
       <startPoint>
          <value1></value1>
          <value2></value2>
       </startPoint>
       <middlePoint>
          <value1></value1>
          <value2></value2>
       </middlePoint>
       <endPoint>
          <value1></value1>
          <value2></value2>
       </endPoint>
   </points>
</element>

StartPoint and Endpoint must occur once, middlepoint can occur many times. I have to transform this in a structure like:

<element>
   <newpoints>
       <pointNumber>
       <value1></value1>
       <value2></value2>       
   </newpoints>
</element>

Obviously newpoints must occur at least twice. Any Suggestion how to combine those points with different attribute-names into the newpoints?

Thanks!

What you should get when you read that data are attributes like:

points.startPoint.value1
points.startPoint.value2
points.middlePoint{}.value1
points.middlePoint{}.value2
points.endpoint.value1
points.endpoint.value2

The {} part in the middlePoint attribute denotes a list, because there can be more than one value.

You can run through that list in the XMLTemplater using something like:

<xml>
{
for $x in fme:get-list-attribute("points.middlePoint{}.value1")
return <list_entry>{$x}</list_entry>
}
</xml>

I can't quite get it to work and I'm afraid I have a meeting to run to now. But I'm hoping this will get you started. The whole template would have the start and end points around the middle ones.

 

 And what I'm really not clear about is nesting those loops - because you need one for value1 and value2. I'm not too hot at XQuery. But like I said, this should be a good starting point.

What you should get when you read that data are attributes like:

points.startPoint.value1
points.startPoint.value2
points.middlePoint{}.value1
points.middlePoint{}.value2
points.endpoint.value1
points.endpoint.value2

The {} part in the middlePoint attribute denotes a list, because there can be more than one value.

You can run through that list in the XMLTemplater using something like:

<xml>
{
for $x in fme:get-list-attribute("points.middlePoint{}.value1")
return <list_entry>{$x}</list_entry>
}
</xml>

I can't quite get it to work and I'm afraid I have a meeting to run to now. But I'm hoping this will get you started. The whole template would have the start and end points around the middle ones.

 

 And what I'm really not clear about is nesting those loops - because you need one for value1 and value2. I'm not too hot at XQuery. But like I said, this should be a good starting point.

OK. It works to an extent. I used this template:

<xml>
<newpoints>
<value1>{fme:get-attribute("points.startPoint.value1")}</value1>
<value2>{fme:get-attribute("points.startPoint.value2")}</value2>
{
    for $x in fme:get-list-attribute("points.middlePoint{}.value1")
    return <value1>{$x}</value1>
}
<value1>{fme:get-attribute("points.endPoint.value1")}</value1>
<value2>{fme:get-attribute("points.endPoint.value2")}</value2>
</newpoints>
</xml

What I can't seem to get is the middle value1/value2 pairings. If I run two for loops consecutively then I get all the value1's then all the value2's.

If I nest the loops I get each value1 paired with each value2, which is also incorrect.

I somehow need to interleave the two queries. Maybe @takashi knows of a way to do this? I will perhaps post it to StackOverflow too, as someone there may know.

 


I think a subtemplate is the way to go here.

Explode the list before the xmltemplater en put it in the subtemplate port.

I include an example to illustrate.subelementsxmltemplaterexample.fmw

Hopes this get you on your way


hmm..., my posts in this thread won't appear anyway.

Retry, again. This is the latest example: xmltemplater-example-4.fmw


I tested these solutions and it works fine for me. ThankYou!


OK. It works to an extent. I used this template:

<xml>
<newpoints>
<value1>{fme:get-attribute("points.startPoint.value1")}</value1>
<value2>{fme:get-attribute("points.startPoint.value2")}</value2>
{
    for $x in fme:get-list-attribute("points.middlePoint{}.value1")
    return <value1>{$x}</value1>
}
<value1>{fme:get-attribute("points.endPoint.value1")}</value1>
<value2>{fme:get-attribute("points.endPoint.value2")}</value2>
</newpoints>
</xml

What I can't seem to get is the middle value1/value2 pairings. If I run two for loops consecutively then I get all the value1's then all the value2's.

If I nest the loops I get each value1 paired with each value2, which is also incorrect.

I somehow need to interleave the two queries. Maybe @takashi knows of a way to do this? I will perhaps post it to StackOverflow too, as someone there may know.

 

 

Hi @Mark2AtSafe, maybe this template expression works as your expected. The combination of temporary XML fragment creation and nested "for" iteration does the trick. Assume that the "_num" attribute stores the number of all points = 2 + number of "points.middlePoint{}" list elements.

<element>
<newpoints>
<pointNumber>1</pointNumber>
<value1>{fme:get-attribute("points.startPoint.value1")}</value1>
<value2>{fme:get-attribute("points.startPoint.value2")}</value2>
{
for $x at $i in fme:get-list-attribute("points.middlePoint{}.value1")
let $a := fn:concat("points.middlePoint{", {$i}-1, "}.value2")
let $t :=<tmp>
    <pointNumber>{fn:sum(({$i}, 1))}</pointNumber>
    <value1>{$x}</value1>
    <value2>{fme:get-attribute($a)}</value2>
    </tmp>
return {for $v in $t/* return $v}
}
<pointNumber>{fme:get-attribute("_num")}</pointNumber>
<value1>{fme:get-attribute("points.endPoint.value1")}</value1>
<value2>{fme:get-attribute("points.endPoint.value2")}</value2>
</newpoints>
</element> 

I don't know why my previous posts in this thread don't appear...

Retry.The attachment is a workspace example using XQuery: xmltemplater-example-2.fmw

lUpdate] xmltemplater-example-3.fmw

pAddition] @Mark2AtSafe, this seems to be a smarter way to manipulate a structured list in an XQuery expression.

<element><newpoints><pointNumber>1</pointNumber><value1>{fme:get-attribute("points.startPoint.value1")}</value1><value2>{fme:get-attribute("points.startPoint.value2")}</value2>{let $v1 := {for $v in fme:get-list-attribute("points.middlePoint{}.value1") return $v}let $v2 := {for $v in fme:get-list-attribute("points.middlePoint{}.value2") return $v}for $i in (1 to fn:count($v1))return (<pointNumber>{fn:sum(($i, 1))}</pointNumber>,    <value1>{$v1f$i]}</value1>,    <value2>{$v2 $i]}</value2>)}<pointNumber>{fme:get-attribute("_num")}</pointNumber><value1>{fme:get-attribute("points.endPoint.value1")}</value1><value2>{fme:get-attribute("points.endPoint.value2")}</value2></newpoints></element>

I don't know why my previous posts in this thread don't appear...

Retry.The attachment is a workspace example using XQuery: xmltemplater-example-2.fmw

lUpdate] xmltemplater-example-3.fmw

pAddition] @Mark2AtSafe, this seems to be a smarter way to manipulate a structured list in an XQuery expression.

<element><newpoints><pointNumber>1</pointNumber><value1>{fme:get-attribute("points.startPoint.value1")}</value1><value2>{fme:get-attribute("points.startPoint.value2")}</value2>{let $v1 := {for $v in fme:get-list-attribute("points.middlePoint{}.value1") return $v}let $v2 := {for $v in fme:get-list-attribute("points.middlePoint{}.value2") return $v}for $i in (1 to fn:count($v1))return (<pointNumber>{fn:sum(($i, 1))}</pointNumber>,    <value1>{$v1f$i]}</value1>,    <value2>{$v2 $i]}</value2>)}<pointNumber>{fme:get-attribute("_num")}</pointNumber><value1>{fme:get-attribute("points.endPoint.value1")}</value1><value2>{fme:get-attribute("points.endPoint.value2")}</value2></newpoints></element>

Simpler XQuery expressions flashed. Nested iteration is not essential in this case :)

XMLTemplater_B:

<element>
<newpoints>
{
for $x at $i in {fme:get-xml-attribute("xml_fragment")}/element/points/*
return (<pointNumber>{$i}</pointNumber>, {$x/value1}, {$x/value2})
}
</newpoints>
</element> 

XMLTemplater_C:

<element>
<newpoints>
<pointNumber>1</pointNumber>
<value1>{fme:get-attribute("points.startPoint.value1")}</value1>
<value2>{fme:get-attribute("points.startPoint.value2")}</value2>
{
for $x at $i in fme:get-list-attribute("points.middlePoint{}.value1")
let $a := fn:concat("points.middlePoint{", {$i}-1, "}.value2")
return (<pointNumber>{sum(($i, 1))}</pointNumber>,
    <value1>{$x}</value1>,
    <value2>{fme:get-attribute($a)}</value2>)
}
<pointNumber>{fme:get-attribute("_num")}</pointNumber>
<value1>{fme:get-attribute("points.endPoint.value1")}</value1>
<value2>{fme:get-attribute("points.endPoint.value2")}</value2>
</newpoints>
</element> 

OK. It works to an extent. I used this template:

<xml>
<newpoints>
<value1>{fme:get-attribute("points.startPoint.value1")}</value1>
<value2>{fme:get-attribute("points.startPoint.value2")}</value2>
{
    for $x in fme:get-list-attribute("points.middlePoint{}.value1")
    return <value1>{$x}</value1>
}
<value1>{fme:get-attribute("points.endPoint.value1")}</value1>
<value2>{fme:get-attribute("points.endPoint.value2")}</value2>
</newpoints>
</xml

What I can't seem to get is the middle value1/value2 pairings. If I run two for loops consecutively then I get all the value1's then all the value2's.

If I nest the loops I get each value1 paired with each value2, which is also incorrect.

I somehow need to interleave the two queries. Maybe @takashi knows of a way to do this? I will perhaps post it to StackOverflow too, as someone there may know.

 

 

OK. It seems that the 'fme:get-list-attribute' function just returns a sequence of values, so this expression is also possible.

<element>
<newpoints>
<pointNumber>1</pointNumber>
<value1>{fme:get-attribute("points.startPoint.value1")}</value1>
<value2>{fme:get-attribute("points.startPoint.value2")}</value2>
{
let $v1 := fme:get-list-attribute("points.middlePoint{}.value1")
let $v2 := fme:get-list-attribute("points.middlePoint{}.value2")
for $i in (1 to fn:count($v1))
return (<pointNumber>{$i + 1}</pointNumber>,
    <value1>{$v1o$i]}</value1>,
    <value2>{$v2&$i]}</value2>)
}
<pointNumber>{fme:get-attribute("_num")}</pointNumber>
<value1>{fme:get-attribute("points.endPoint.value1")}</value1>
<value2>{fme:get-attribute("points.endPoint.value2")}</value2>
</newpoints>
</element> 

What you should get when you read that data are attributes like:

points.startPoint.value1
points.startPoint.value2
points.middlePoint{}.value1
points.middlePoint{}.value2
points.endpoint.value1
points.endpoint.value2

The {} part in the middlePoint attribute denotes a list, because there can be more than one value.

You can run through that list in the XMLTemplater using something like:

<xml>
{
for $x in fme:get-list-attribute("points.middlePoint{}.value1")
return <list_entry>{$x}</list_entry>
}
</xml>

I can't quite get it to work and I'm afraid I have a meeting to run to now. But I'm hoping this will get you started. The whole template would have the start and end points around the middle ones.

 

 And what I'm really not clear about is nesting those loops - because you need one for value1 and value2. I'm not too hot at XQuery. But like I said, this should be a good starting point.

This expression also works. # hopefully this post will appear...

<element>
<newpoints>
<pointNumber>1</pointNumber>
<value1>{fme:get-attribute("points.startPoint.value1")}</value1>
<value2>{fme:get-attribute("points.startPoint.value2")}</value2>
{
for $i in (0 to fn:count(fme:get-list-attribute("points.middlePoint{}.value1")) - 1)
return (<pointNumber>{$i + 2}</pointNumber>,
<value1>{fme:get-attribute(fn:concat("points.middlePoint{", $i, "}.value1"))}</value1>,
<value2>{fme:get-attribute(fn:concat("points.middlePoint{", $i, "}.value2"))}</value2>)
}
<pointNumber>{
fn:count(fme:get-list-attribute("points.middlePoint{}.value1")) + 2
}</pointNumber>
<value1>{fme:get-attribute("points.endPoint.value1")}</value1>
<value2>{fme:get-attribute("points.endPoint.value2")}</value2>
</newpoints>
</element><br>

the XMLXQueryUpdater may be a better choice in this case. My final example: xqueryupdater-example.fmw


hmm..., my posts in this thread won't appear anyway.

Retry, again. This is the latest example: xmltemplater-example-4.fmw

ok. my previous posts all are displayed now. I've removed excess posts.


Reply