Skip to main content
Question

Extract attributes from XML attribute


robert_punt
Contributor
Forum|alt.badge.img+6

Hi everyone, i have a xml question. In my data (dgn V8) i have an attribute called

igds_linkage{}.xml_data.

It lookes like this:

What i want is to extract the attribute with their value.

For example: attribute = 'Type' Value= 'muur' & attribute= 'IMGEO' Value='bestaand'

I now use an xmlflattener

But my result is an list like this.

You can see that the first item in the list has a different attribute value 'identificatieBAGPND' in stead of Type.

So how can i get the attribute and value from the xml and can i make it dynamic. (extract all list items in to attributes)

12 replies

jdh
Contributor
Forum|alt.badge.img+28
  • Contributor
  • August 22, 2017

If you use the XMLFragmenter with Elements to Match set to "feature" and flattening enabled you will end up with a key-value pair list for each feature

ex.

 

'attribuut{0}' has value `muur'

 

'attribuut{0}.naam' has value `type'

 

'attribuut{1}' has value `bestaad'

 

'attribuut{1}.naam' has value `IMGEO status'

You can then loop through the list and turn each element pair into an attribute.

ex with an attribute creator

@Value(attribuut{0}.naam) ; attribuut{0}

 

If on the other hand you want one feature per attribute you can set the fragmenter to attribuut and you will end up with attribuut = muur, attribuut.naam = type, and you can do the same thing without the list indexes.


takashi
Influencer
  • August 23, 2017

I also think @jdh's solution is good enough, but, sorry, I cannot resist to try an XQuery solution...


Assuming the feature has an attribute called "xml_fragment" that stores an XML fragment. e.g.

<SHD>
    <feature datadefinitie="Sleutels" code="SLEUTELS">
        <attribuut naam="gisobjectnummeer">105963</attribuut>
    </feature>
    <feature datadefinitie="IMG" code="SHDV">
        <attribuut naam="type">muur</attribuut>
        <attribuut naam="IMGEO status">bestaand</attribuut>
        <attribuut naam="In onderzoek">Nee</attribuut>
        <attribuut naam="relatieveHoogteligging">0</attribuut>
        <attribuut naam="identificatie">P0027.cdffbb11ae7c4f56a96af8f6c17cefb5</attribuut>
        <attribuut naam="tijadstipRegistratie">20170626172844000</attribuut>
    </feature>
    <feature datadefinitie="GBK_LKI" code="C"></feature>
</SHD>
A JSONTemplater with this expression creates the following JSON object.JSONTemplater | Template Expression (XQuery expression)
let $x := fme:get-xml-attribute("xml_fragment")
let $members := {
    for $a in $x//attribuut
    return '"'||string($a/@naam)||'":"'||$a/text()||'"'
}
return '{'||fn:string-join($members',')||'}'
Resulting JSON Object:

 

{
   "gisobjectnummeer" : "105963",
   "type" : "muur",
   "IMGEO status" : "bestaand",
   "In onderzoek" : "Nee",
   "relatieveHoogteligging" : "0",
   "identificatie" : "P0027.cdffbb11ae7c4f56a96af8f6c17cefb5",
   "tijadstipRegistratie" : "20170626172844000"
}
You can then extract and expose individual attributes with a JSONFlattener.

robert_punt
Contributor
Forum|alt.badge.img+6
  • Author
  • Contributor
  • August 23, 2017
jdh wrote:

If you use the XMLFragmenter with Elements to Match set to "feature" and flattening enabled you will end up with a key-value pair list for each feature

ex.

 

'attribuut{0}' has value `muur'

 

'attribuut{0}.naam' has value `type'

 

'attribuut{1}' has value `bestaad'

 

'attribuut{1}.naam' has value `IMGEO status'

You can then loop through the list and turn each element pair into an attribute.

ex with an attribute creator

@Value(attribuut{0}.naam) ; attribuut{0}

 

If on the other hand you want one feature per attribute you can set the fragmenter to attribuut and you will end up with attribuut = muur, attribuut.naam = type, and you can do the same thing without the list indexes.

@jdh thank you for your solution. the only problem i have is to make the attribuut{}.naam the attribute name and the attribuut{} value the value of attribuut.naam{}.

 

Every object has its own attributes so i have to split every object and define its attributes.

 


robert_punt
Contributor
Forum|alt.badge.img+6
  • Author
  • Contributor
  • August 23, 2017
takashi wrote:

I also think @jdh's solution is good enough, but, sorry, I cannot resist to try an XQuery solution...


Assuming the feature has an attribute called "xml_fragment" that stores an XML fragment. e.g.

<SHD>
    <feature datadefinitie="Sleutels" code="SLEUTELS">
        <attribuut naam="gisobjectnummeer">105963</attribuut>
    </feature>
    <feature datadefinitie="IMG" code="SHDV">
        <attribuut naam="type">muur</attribuut>
        <attribuut naam="IMGEO status">bestaand</attribuut>
        <attribuut naam="In onderzoek">Nee</attribuut>
        <attribuut naam="relatieveHoogteligging">0</attribuut>
        <attribuut naam="identificatie">P0027.cdffbb11ae7c4f56a96af8f6c17cefb5</attribuut>
        <attribuut naam="tijadstipRegistratie">20170626172844000</attribuut>
    </feature>
    <feature datadefinitie="GBK_LKI" code="C"></feature>
</SHD>
A JSONTemplater with this expression creates the following JSON object.JSONTemplater | Template Expression (XQuery expression)
let $x := fme:get-xml-attribute("xml_fragment")
let $members := {
    for $a in $x//attribuut
    return '"'||string($a/@naam)||'":"'||$a/text()||'"'
}
return '{'||fn:string-join($members',')||'}'
Resulting JSON Object:

 

{
   "gisobjectnummeer" : "105963",
   "type" : "muur",
   "IMGEO status" : "bestaand",
   "In onderzoek" : "Nee",
   "relatieveHoogteligging" : "0",
   "identificatie" : "P0027.cdffbb11ae7c4f56a96af8f6c17cefb5",
   "tijadstipRegistratie" : "20170626172844000"
}
You can then extract and expose individual attributes with a JSONFlattener.
@takashi Thank you for your solution. the json is new for me and i think i give it a try.

 


mark2atsafe
Safer
Forum|alt.badge.img+44
  • Safer
  • August 23, 2017
robert_punt wrote:
@jdh thank you for your solution. the only problem i have is to make the attribuut{}.naam the attribute name and the attribuut{} value the value of attribuut.naam{}.

 

Every object has its own attributes so i have to split every object and define its attributes.

 

And that's where the @Value(attribuut{0}.naam) ; attribuut{0} part comes in - if you put that in an AttributeCreator it will create the attributes you need.

 

 

That technique is what I first thought of too - but perhaps there is a better way. I will look into it.

 


jdh
Contributor
Forum|alt.badge.img+28
  • Contributor
  • August 23, 2017
mark2atsafe wrote:
And that's where the @Value(attribuut{0}.naam) ; attribuut{0} part comes in - if you put that in an AttributeCreator it will create the attributes you need.

 

 

That technique is what I first thought of too - but perhaps there is a better way. I will look into it.

 

I actually still use the fme function caller with @SupplyAttributes, but that's a bit esoteric. If I don't need to access the attributes later in the workspace (just write them out dynamically) I would use python.

 


mark2atsafe
Safer
Forum|alt.badge.img+44
  • Safer
  • August 23, 2017

Ah! I see there is already a custom transformer on the FME Hub that will do what you need.

So... do as @jdh suggests and use the XMLFragmenter to create your list of attributes.

Then use a ListKeyValuePairExtractor transformer (you might need FME2017.1) and it will convert your list into true attributes. Simple.


mark2atsafe
Safer
Forum|alt.badge.img+44
  • Safer
  • August 23, 2017
mark2atsafe wrote:

Ah! I see there is already a custom transformer on the FME Hub that will do what you need.

So... do as @jdh suggests and use the XMLFragmenter to create your list of attributes.

Then use a ListKeyValuePairExtractor transformer (you might need FME2017.1) and it will convert your list into true attributes. Simple.

Nice work @sander_s for the hub transformer. Very useful.

 


takashi
Influencer
  • August 23, 2017
takashi wrote:

I also think @jdh's solution is good enough, but, sorry, I cannot resist to try an XQuery solution...


Assuming the feature has an attribute called "xml_fragment" that stores an XML fragment. e.g.

<SHD>
    <feature datadefinitie="Sleutels" code="SLEUTELS">
        <attribuut naam="gisobjectnummeer">105963</attribuut>
    </feature>
    <feature datadefinitie="IMG" code="SHDV">
        <attribuut naam="type">muur</attribuut>
        <attribuut naam="IMGEO status">bestaand</attribuut>
        <attribuut naam="In onderzoek">Nee</attribuut>
        <attribuut naam="relatieveHoogteligging">0</attribuut>
        <attribuut naam="identificatie">P0027.cdffbb11ae7c4f56a96af8f6c17cefb5</attribuut>
        <attribuut naam="tijadstipRegistratie">20170626172844000</attribuut>
    </feature>
    <feature datadefinitie="GBK_LKI" code="C"></feature>
</SHD>
A JSONTemplater with this expression creates the following JSON object.JSONTemplater | Template Expression (XQuery expression)
let $x := fme:get-xml-attribute("xml_fragment")
let $members := {
    for $a in $x//attribuut
    return '"'||string($a/@naam)||'":"'||$a/text()||'"'
}
return '{'||fn:string-join($members',')||'}'
Resulting JSON Object:

 

{
   "gisobjectnummeer" : "105963",
   "type" : "muur",
   "IMGEO status" : "bestaand",
   "In onderzoek" : "Nee",
   "relatieveHoogteligging" : "0",
   "identificatie" : "P0027.cdffbb11ae7c4f56a96af8f6c17cefb5",
   "tijadstipRegistratie" : "20170626172844000"
}
You can then extract and expose individual attributes with a JSONFlattener.
wow, I found that the XMLXQueryUpdater can be used to extract individual attributes directly from the XML fragment with this small expression.

 

for $a in //attribuut
return fme:set-attribute($a/@naam, $a/text())

0684Q00000ArMQGQA3.png

Interesting. It would be more useful if the Attributes to Expose parameters would be added to the transformer.

takashi
Influencer
  • August 24, 2017
takashi wrote:

I also think @jdh's solution is good enough, but, sorry, I cannot resist to try an XQuery solution...


Assuming the feature has an attribute called "xml_fragment" that stores an XML fragment. e.g.

<SHD>
    <feature datadefinitie="Sleutels" code="SLEUTELS">
        <attribuut naam="gisobjectnummeer">105963</attribuut>
    </feature>
    <feature datadefinitie="IMG" code="SHDV">
        <attribuut naam="type">muur</attribuut>
        <attribuut naam="IMGEO status">bestaand</attribuut>
        <attribuut naam="In onderzoek">Nee</attribuut>
        <attribuut naam="relatieveHoogteligging">0</attribuut>
        <attribuut naam="identificatie">P0027.cdffbb11ae7c4f56a96af8f6c17cefb5</attribuut>
        <attribuut naam="tijadstipRegistratie">20170626172844000</attribuut>
    </feature>
    <feature datadefinitie="GBK_LKI" code="C"></feature>
</SHD>
A JSONTemplater with this expression creates the following JSON object.JSONTemplater | Template Expression (XQuery expression)
let $x := fme:get-xml-attribute("xml_fragment")
let $members := {
    for $a in $x//attribuut
    return '"'||string($a/@naam)||'":"'||$a/text()||'"'
}
return '{'||fn:string-join($members',')||'}'
Resulting JSON Object:

 

{
   "gisobjectnummeer" : "105963",
   "type" : "muur",
   "IMGEO status" : "bestaand",
   "In onderzoek" : "Nee",
   "relatieveHoogteligging" : "0",
   "identificatie" : "P0027.cdffbb11ae7c4f56a96af8f6c17cefb5",
   "tijadstipRegistratie" : "20170626172844000"
}
You can then extract and expose individual attributes with a JSONFlattener.
The XMLXQueryExtractor does the same thing, and also it has the "Attributes to Expose" parameter, so it might be better in this case.

 

0684Q00000ArMTSQA3.png


robert_punt
Contributor
Forum|alt.badge.img+6
  • Author
  • Contributor
  • August 24, 2017
takashi wrote:

I also think @jdh's solution is good enough, but, sorry, I cannot resist to try an XQuery solution...


Assuming the feature has an attribute called "xml_fragment" that stores an XML fragment. e.g.

<SHD>
    <feature datadefinitie="Sleutels" code="SLEUTELS">
        <attribuut naam="gisobjectnummeer">105963</attribuut>
    </feature>
    <feature datadefinitie="IMG" code="SHDV">
        <attribuut naam="type">muur</attribuut>
        <attribuut naam="IMGEO status">bestaand</attribuut>
        <attribuut naam="In onderzoek">Nee</attribuut>
        <attribuut naam="relatieveHoogteligging">0</attribuut>
        <attribuut naam="identificatie">P0027.cdffbb11ae7c4f56a96af8f6c17cefb5</attribuut>
        <attribuut naam="tijadstipRegistratie">20170626172844000</attribuut>
    </feature>
    <feature datadefinitie="GBK_LKI" code="C"></feature>
</SHD>
A JSONTemplater with this expression creates the following JSON object.JSONTemplater | Template Expression (XQuery expression)
let $x := fme:get-xml-attribute("xml_fragment")
let $members := {
    for $a in $x//attribuut
    return '"'||string($a/@naam)||'":"'||$a/text()||'"'
}
return '{'||fn:string-join($members',')||'}'
Resulting JSON Object:

 

{
   "gisobjectnummeer" : "105963",
   "type" : "muur",
   "IMGEO status" : "bestaand",
   "In onderzoek" : "Nee",
   "relatieveHoogteligging" : "0",
   "identificatie" : "P0027.cdffbb11ae7c4f56a96af8f6c17cefb5",
   "tijadstipRegistratie" : "20170626172844000"
}
You can then extract and expose individual attributes with a JSONFlattener.
The xmlXQueryExtractor does the job. exactly what i was looking for. Thank you @takashi

 


jurgenmack
Contributor
Forum|alt.badge.img+9
  • Contributor
  • January 17, 2018
jdh wrote:

If you use the XMLFragmenter with Elements to Match set to "feature" and flattening enabled you will end up with a key-value pair list for each feature

ex.

 

'attribuut{0}' has value `muur'

 

'attribuut{0}.naam' has value `type'

 

'attribuut{1}' has value `bestaad'

 

'attribuut{1}.naam' has value `IMGEO status'

You can then loop through the list and turn each element pair into an attribute.

ex with an attribute creator

@Value(attribuut{0}.naam) ; attribuut{0}

 

If on the other hand you want one feature per attribute you can set the fragmenter to attribuut and you will end up with attribuut = muur, attribuut.naam = type, and you can do the same thing without the list indexes.

I have exposed 39 attribute pairs along with the default xml attributes using the XML-Fragmenter. They are in the form: Property || Value in the FME Data Inspector. None of the methods above allow me to extract these values.

 

 


Cookie policy

We use cookies to enhance and personalize your experience. If you accept you agree to our full cookie policy. Learn more about our cookies.

 
Cookie settings