Question

XML Templater empty subtemplate

  • 12 September 2017
  • 2 replies
  • 4 views

Badge +22
  • Contributor
  • 1961 replies

I am looking for a way to have a "default value"  if there is no data in a subtemplate.

 

 

Consider the house, village example from the help documentation.  If we have multiple villages with an id, and multiple houses with a village_id,  we can set the Root template to 

<village>
<name>{fme:get-attribute("name")}</name>
<population>{fme:get-attribute("population")}</population>
<houses>
{fme:process-features("HOUSE", "village_id", fme:get-attribute("id"))}
</houses>
</village>

and the correct houses will be associated with the correct village.

 

and you could end up with an output like

 

<village>
<name>Anytown, USA</name>
<population>2568</population>
<houses>
<house>
<address>123 Main Street</address>
<owner>John Doe</owner>
</house>
<house>
<address>324 Main Street</address>
<owner>Jane Doe</owner>
</house>
</houses>
</village>

However if there are no houses for a specific village, the result is

<village>
<name>Anytown, USA</name>
<population>2568</population>
<houses>

 </houses>
</village>
Instead of empty space, I would like to specify an alternate value.

Something like

<village>
<name>Anytown, USA</name>
<population>2568</population>
<houses>No houses available</houses>
</village>

In my data the root feature (village) has no information as to the number of subfeatures (houses) associated with it, so I can't simply use a conditional like

<houses>
{ if( (fme:get-attribute("housecount") eq "0") )
then {fme:process-features("HOUSE", "village_id", fme:get-attribute("id"))}
else "No houses available" 
}
</houses>

Any thoughts?  I have several thousand root features and several hundred thousand subfeatures so I would like to avoid using a featureMerger on the data prior to the XMLTemplater if at all possible.


2 replies

Userlevel 3
Badge +17

Hi @jdh, this expression might help you.

<village>
<name>{fme:get-attribute("name")}</name>
<population>{fme:get-attribute("population")}</population>
{
let $houses := <houses>{
    fme:process-features("HOUSE", "village_id", fme:get-attribute("id"))
}</houses>
return if (0 < fn:count($houses/house))
then $houses
else <houses>No houses available</houses> 
}
</village>
Userlevel 3
Badge +17

Hi @jdh, this expression might help you.

<village>
<name>{fme:get-attribute("name")}</name>
<population>{fme:get-attribute("population")}</population>
{
let $houses := <houses>{
    fme:process-features("HOUSE", "village_id", fme:get-attribute("id"))
}</houses>
return if (0 < fn:count($houses/house))
then $houses
else <houses>No houses available</houses> 
}
</village>
This expression is also available.

 

<village>
<name>{fme:get-attribute("name")}</name>
<population>{fme:get-attribute("population")}</population>
<houses>{
let $houses := {
    fme:process-features("HOUSE", "village_id", fme:get-attribute("id"))
}
return
if (0 < fn:count($houses)) then $houses else "No houses available"
}</houses>
</village>
For what it's worth, in my experiences, XMLTemplater with a sub template worked not so efficient in many cases. Depending on the conditions, processing a list attribute within a single root expression could be faster. e.g.

0684Q00000ArMhGQAV.png

<village>
<name>{fme:get-attribute("name")}</name>
<population>{fme:get-attribute("population")}</population>
<houses>{
let $houses := {
    let $owners := fme:get-list-attribute("_list{}.owner")
    for $address at $i in fme:get-list-attribute("_list{}.address")
    return
    <house>
        <address>{$address}</address>
        <owner>{$owners[$i]}</owner>
    </house>
}
return
if (0 < fn:count($houses)) then $houses else "No houses available"
}</houses>
</village><br>

Reply