Question

XML Text to split into a list


Badge

Hi,

I have a XML Templater i filled with data to match a structured record and i obtain this:

 

<aixm:annotation xmlns:aixm="http://www.aixm.aero/schema/5.1">

 

<aixm:Note xmlns:gml="http://www.opengis.net/gml/3.2" gml:id="nresp_1520862_0">

 

<aixm:purpose>DESCRIPTION</aixm:purpose>

 

<aixm:translatedNote>

 

<aixm:LinguisticNote gml:id="lnresp_1520862_0">

 

<aixm:note>Site description: 10 km Ouest de Bordeaux\\\\10 km West of Bordeaux</aixm:note>

 

</aixm:LinguisticNote>

 

</aixm:translatedNote>

 

</aixm:Note>

 

</aixm:annotation>

<aixm:annotation xmlns:aixm="http://www.aixm.aero/schema/5.1">

 

<aixm:Note xmlns:gml="http://www.opengis.net/gml/3.2" gml:id="noresp_1520862_0">

 

<aixm:purpose>DESCRIPTION</aixm:purpose>

 

<aixm:translatedNote>

 

<aixm:LinguisticNote gml:id="lnoresp_1520862_0">

 

<aixm:note>Organisation in charge: SA-ADBM</aixm:note>

 

</aixm:LinguisticNote>

 

</aixm:translatedNote>

 

</aixm:Note>

 

</aixm:annotation>

<aixm:annotation xmlns:aixm="http://www.aixm.aero/schema/5.1">

 

<aixm:Note xmlns:gml="http://www.opengis.net/gml/3.2" gml:id="arprefresp_1520862_0">

 

<aixm:propertyName xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance">arp</aixm:propertyName>

 

<aixm:purpose>DESCRIPTION</aixm:purpose>

 

<aixm:translatedNote>

 

<aixm:LinguisticNote gml:id="lnarpresp_1520862_0">

 

<aixm:note>Intersection des pistes en béton\\\\Concrete RWY intersection</aixm:note>

 

</aixm:LinguisticNote>

 

</aixm:translatedNote>

 

</aixm:Note>

 

</aixm:annotation>

I would like to keep each <aixm:annotation> ..... </aixm:annotation> (3 in this example) in a list which name is annotation {0} for the first record, annotation {1} for the second ....

I don't succeed ...some advice ?


6 replies

Userlevel 2
Badge +17

Hi @philippe33, the XMLFragmenter might help you. Assuming that the name of the parent element of the annotation elements is "parent", fragment the XML document with these parameters.

  • Elements to Match: parent
  • Elements as XML Fragments: annotation
  • Attributes to Expose: xml_fragment_annotation{}

The XMLFragmenter outputs a feature containing a list called "xml_fragment_annotation{}" which stores every annotation XML fragment as its elements. You can then rename the list to "annotation{}" with the ListRenamer or the AttributeManager.

Hope this helps.

Badge

Hi @takashi

I give some precisions about my request. i don't speak english a lot

My problem : With XML templater i test if some attributes exist or not. If they exist, i write a small part of XML for each attributes which are found. A little xml fragment if i find attribute "X", a little xml fragment for the attribute "Y" .... i make 3 tests

templater.png

the XML part is like this :

templater-xml.png

I obtain a lot of result with the templater. For one feature i can obtain 3 elements XML maximum

 

xmltemplater-output.png

 

At the end, in the final schema i have to write in a list, not in a xml fragment

ecriture.png

with the xml_fragmenter it make me the job only one time per feature in input. if it had many "annotation" in the xml fragment it gives me an error

erreur.png

some advice ?

Userlevel 2
Badge +17

With the limited information, it's hard to understand correctly what you intend to do.

If you are going to create 932 <annotation> fragments for each input feature, and the contents could be different depending on attribute value(s) of the input feature, this mock-up ROOT template might be helpful. Assuming that the input feature has an attribute called "n" and it can store 0, 1, or other.

<annotation>{
let $n := fme:get-attribute("n")
return
    if ($n eq 0) then {
        <foo />
    }
    else if ($n eq 1) then {
        <bar />
    }
    else {
        <foobar />
    }
}</annotation>

Naturally the contents corresponding to each condition can also be supplied by SUB templates, but you will have to set the "Group Sub-Features By" parameter to group a ROOT feature and corresponding SUB features. The ROOT template looks like this. Assuming that X, Y, and Z are the sub template port names. 

<annotation>{
let $n := fme:get-attribute("n")
return
    if ($n eq 0) then {
        fme:process-features("X")
    }
    else if ($n eq 1) then {
        fme:process-features("Y")
    }
    else {
        fme:process-features("Z")
    }
}</annotation>

Badge

airportheliport51-fme2016.fmw

Userlevel 2
Badge +17

Your template expression generates a sequence of 0 - 3 annotation elements, but they cannot be handled as an XML fragment in the subsequent workflow, since they don't belong to a common parent.

If you use the XMLFragmenter to populate the annotation elements to a list, you have to fix the expression to generate a single XML element that contains the annotation elements as children. e.g.

(: replace [condition] with the actual condition expression :)
(: Update: Changed every "fme:process-features" to "fme:process-template" :)
<parent>{
    {
        if ([condition]) then {fme:process-template("X")}
        else ()
    },
    {
        if ([condition]) then {fme:process-template("Y")}
        else ()
    },
    {
        if ([condition]) then {fme:process-template("Z")}
        else ()
    }
}</parent>

Alternatively, the StringSearcher could be used to populate the annotation elements to a list. Set this regular expression and specify "All Matches List Name".

<aixm:annotation.+?</aixm:annotation>
Anyway, I think you will have to use the "Group Sub-Features By" parameter in the XMLTemplater_6 to group a ROOT and a set of X, Y, and Z.

[Update] I didn't notice that you are using the "fme:process-template" function in the template expression, rather than the "fme:process-features" function.
If you use the "fme:process-template" function, it may not be essential to set the "Group Sub-Features By" parameter. 

Userlevel 2
Badge +17

It seems that the only difference among X, Y, and Z expressions is the contents of the <aixm:note> element. If I have understood your intention correctly, the four expressions (ROOT, X, Y, and Z) could be integrated/simplified into a single ROOT expression like this.

declare namespace aixm="http://www.aixm.aero/schema/5.1";
declare namespace gml="http://www.opengis.net/gml/3.2";
<parent>{
    let $id := fme:get-attribute("gml_id")
    let $texts := (
        {
            let $t := fme:get-attribute("txtDescrSite")
            return if ($t ne "") then "Site description: "||$t else ""
        },
        {
            let $t := fme:get-attribute("txtNameAdmin")
            return if ($t ne "") then "Organisation in charge: "||$t else ""
        },
        {
            let $t := fme:get-attribute("txtDescrRefPt")
            return if ($t ne "") then $t else ""
        }
    )
    for $txt in $texts where $txt ne ""
    return
    <aixm:annotation>
        <aixm:Note gml:id="{"n"||$id||"_0"}">
            <aixm:purpose>DESCRIPTION</aixm:purpose>
            <aixm:translatedNote>
                <aixm:LinguisticNote gml:id="{"ln"||$id||"_0"}">
                    <aixm:note>{$txt}</aixm:note>
                </aixm:LinguisticNote>
            </aixm:translatedNote>
        </aixm:Note>
    </aixm:annotation>
}</parent>

If you don't need to surround the sequence of <aixm:annotation> elements by the <parent> element, remove these two lines from the expression above.

<parent>{
}</parent>

Reply