Question

updating xml -- figuring out if a node is missing and needs to be added or there and update with new content

  • 27 September 2017
  • 10 replies
  • 11 views

Badge +9

I am attempting to update an xml attribute (geodb_metadata_file) for multiple features. Some features have more xml content than others. I need to figure out which nodes are missing and will add content and which nodes are there and need to update content. There are about 7 nodes that I am testing but could be more so I need a generic way to test. a "for each" loop through a list of nodes to test and pathing the result into either update or add is my pseudo solution, but I don't know how to do that in a workspace except to have multiple testers which feels wrong.

Please help!


10 replies

Userlevel 4
Badge +30

Hi @tnarladni,

This post that you created is not good for you?

XML

Thanks,

Danilo

Badge +9

Hi @tnarladni,

This post that you created is not good for you?

XML

Thanks,

Danilo

the problem is that I am trying to expand upon that script and putting in multiple testers, 7 testers for the 7 nodes and 14 xmlUpdaters (2 for each nodes depending on if I'm adding or updating) works but is very messy. I'm trying to find a more efficient way to do it.

 

 

Userlevel 4
Badge +30
the problem is that I am trying to expand upon that script and putting in multiple testers, 7 testers for the 7 nodes and 14 xmlUpdaters (2 for each nodes depending on if I'm adding or updating) works but is very messy. I'm trying to find a more efficient way to do it.

 

 

About the transformer 7 Tester you can to replace with a simple transformer TestFilter.

 

 

Badge +9

Hi @tnarladni,

This post that you created is not good for you?

XML

Thanks,

Danilo

except the nodes are independent of each other and multiple nodes could be missing so a testFilter will not work. I would have to test for each node independently. with the testFilter, once features go out one port, it will not go out the other ports.

 

 

Userlevel 2
Badge +17

Hi @tnarladni, a possible way is to run an XQuery expression to once delete all the target nodes and then reinsert the nodes with new values.

For example, assume the original XML document was

<root>
    <parent>
        <a>xxx</a>
        <c>zzz</c>
    </parent>
</root>

the XMLXQueryUpdater with this XQuery expression

(: Once delete all the target nodes. :)
let $nodes := (//parent/a, //parent/b, //parent/c)
for $x in $nodes return delete node $x,

(: Reinsert the nodes with new values. :)
insert nodes (
    <a>foo</a>,
    <b>bar</b>,
    <c>foobar</c>
) as first into //parent

updates the original XML to this one.

<root>
    <parent>
        <a>foo</a>
        <b>bar</b>
        <c>foobar</c>
    </parent>
</root>

There should be uncountable variations depending on the actual XML schema and requirements.

Userlevel 2
Badge +17

Hi @tnarladni, a possible way is to run an XQuery expression to once delete all the target nodes and then reinsert the nodes with new values.

For example, assume the original XML document was

<root>
    <parent>
        <a>xxx</a>
        <c>zzz</c>
    </parent>
</root>

the XMLXQueryUpdater with this XQuery expression

(: Once delete all the target nodes. :)
let $nodes := (//parent/a, //parent/b, //parent/c)
for $x in $nodes return delete node $x,

(: Reinsert the nodes with new values. :)
insert nodes (
    <a>foo</a>,
    <b>bar</b>,
    <c>foobar</c>
) as first into //parent

updates the original XML to this one.

<root>
    <parent>
        <a>foo</a>
        <b>bar</b>
        <c>foobar</c>
    </parent>
</root>

There should be uncountable variations depending on the actual XML schema and requirements.

Of course you can assign the values of feature attributes to the nodes.

 

(: Once delete all the target nodes. :)
let $nodes := (//parent/a, //parent/b, //parent/c)
for $x in $nodes return delete node $x,

(: Reinsert the nodes with new values. :)
insert nodes (
    <a>{fme:get-attribute("a")}</a>,
    <b>{fme:get-attribute("b")}</b>,
    <c>{fme:get-attribute("c")}</c>
) as first into //parent 
Badge +9

Hi @tnarladni, a possible way is to run an XQuery expression to once delete all the target nodes and then reinsert the nodes with new values.

For example, assume the original XML document was

<root>
    <parent>
        <a>xxx</a>
        <c>zzz</c>
    </parent>
</root>

the XMLXQueryUpdater with this XQuery expression

(: Once delete all the target nodes. :)
let $nodes := (//parent/a, //parent/b, //parent/c)
for $x in $nodes return delete node $x,

(: Reinsert the nodes with new values. :)
insert nodes (
    <a>foo</a>,
    <b>bar</b>,
    <c>foobar</c>
) as first into //parent

updates the original XML to this one.

<root>
    <parent>
        <a>foo</a>
        <b>bar</b>
        <c>foobar</c>
    </parent>
</root>

There should be uncountable variations depending on the actual XML schema and requirements.

xQuery is so powerful, and I don't know how to use it! Once again @takashi, you have saved my bacon. Thank you!
Userlevel 2
Badge +17

Hi @tnarladni, a possible way is to run an XQuery expression to once delete all the target nodes and then reinsert the nodes with new values.

For example, assume the original XML document was

<root>
    <parent>
        <a>xxx</a>
        <c>zzz</c>
    </parent>
</root>

the XMLXQueryUpdater with this XQuery expression

(: Once delete all the target nodes. :)
let $nodes := (//parent/a, //parent/b, //parent/c)
for $x in $nodes return delete node $x,

(: Reinsert the nodes with new values. :)
insert nodes (
    <a>foo</a>,
    <b>bar</b>,
    <c>foobar</c>
) as first into //parent

updates the original XML to this one.

<root>
    <parent>
        <a>foo</a>
        <b>bar</b>
        <c>foobar</c>
    </parent>
</root>

There should be uncountable variations depending on the actual XML schema and requirements.

Good to hear it helps you. Besides, this simple syntax is also available to delete multiple nodes at once.

 

(: Once delete all the target nodes. :)
delete nodes (
    //parent/a,
    //parent/b,
    //parent/c
),

(: Reinsert the nodes with new values. :)
insert nodes (
...
Badge +9

Hi @tnarladni, a possible way is to run an XQuery expression to once delete all the target nodes and then reinsert the nodes with new values.

For example, assume the original XML document was

<root>
    <parent>
        <a>xxx</a>
        <c>zzz</c>
    </parent>
</root>

the XMLXQueryUpdater with this XQuery expression

(: Once delete all the target nodes. :)
let $nodes := (//parent/a, //parent/b, //parent/c)
for $x in $nodes return delete node $x,

(: Reinsert the nodes with new values. :)
insert nodes (
    <a>foo</a>,
    <b>bar</b>,
    <c>foobar</c>
) as first into //parent

updates the original XML to this one.

<root>
    <parent>
        <a>foo</a>
        <b>bar</b>
        <c>foobar</c>
    </parent>
</root>

There should be uncountable variations depending on the actual XML schema and requirements.

@takashi so when I run this on production, I get error messages that the //parent does not exist. and it's true that some of the xml documents will not have that //parent element. After much trial and errors I figured out (yah me!) the code to see if that //parent element exists. The problem is, the simple script works:

 

 

0684Q00000ArMPoQAN.png

 

But as part of the delete/insert script, it fails:

 

 

0684Q00000ArMb8QAF.png

 

Please, could you help? TIA

 

 

Userlevel 2
Badge +17

Hi @tnarladni, a possible way is to run an XQuery expression to once delete all the target nodes and then reinsert the nodes with new values.

For example, assume the original XML document was

<root>
    <parent>
        <a>xxx</a>
        <c>zzz</c>
    </parent>
</root>

the XMLXQueryUpdater with this XQuery expression

(: Once delete all the target nodes. :)
let $nodes := (//parent/a, //parent/b, //parent/c)
for $x in $nodes return delete node $x,

(: Reinsert the nodes with new values. :)
insert nodes (
    <a>foo</a>,
    <b>bar</b>,
    <c>foobar</c>
) as first into //parent

updates the original XML to this one.

<root>
    <parent>
        <a>foo</a>
        <b>bar</b>
        <c>foobar</c>
    </parent>
</root>

There should be uncountable variations depending on the actual XML schema and requirements.

If there could be a case where the parent node doesn't exist, and you need to insert a parent node with a full set of child nodes in that case, this approach might help you.

 

(: Create a new parent node with a full set of child nodes :)
let $p :=
<parent>
    <a>{fme:get-attribute("a")}</a>
    <b>{fme:get-attribute("b")}</b>
    <c>{fme:get-attribute("c")}</c>
</parent>
return
if (fn:exists(//parent)) then
    (: Replace the existing parent node with the new parent node :)
    replace node //parent with $p 
else
    (: Insert the new parent node into the grandparent node :)
    insert node $p as first into //root 

Reply