0
votes

I need to insert a new element inside multiple nodes into an input XML document. Then, I need to update and retrieve the updated XML document.

I'm using Anypoint Studio, and since the xquery Transformation module supports XQuery 3.0, I figured that I can use the insert-before function, and since the element must be inserted in multiple nodes, I need to use a for loop to cycle through the multiple matches.

I'm new to xQuery so I apologize in advance for any beginner-type errors.

Here's a sample of the XML document I need to transform:

<Catalog>
  <Item>
    <Property1>Prop1</Property1>
    <Property2>Prop2</Property2>
    <Property3>Prop3</Property3>
  </Item>
  <Item>
    <Property1>Prop1</Property1>
    <Property2>Prop2</Property2>
    <Property3>Prop3</Property3>
  </Item>
  <Item>
    <Property1>Prop1</Property1>
    <Property2>Prop2</Property2>
    <Property3>Prop3</Property3>
  </Item>
</Catalog>

I need to insert the tag Name in position 1 of every Item node. Something like this:

<Catalog>
  <Item>
    <Name>SomeName1</Name>
    <Property1>Prop1</Property1>
    <Property2>Prop2</Property2>
    <Property3>Prop3</Property3>
  </Item>
  <Item>
    <Name>SomeName2</Name>
    <Property1>Prop1</Property1>
    <Property2>Prop2</Property2>
    <Property3>Prop3</Property3>
  </Item>
  <Item>
    <Name>SomeName3</Name>
    <Property1>Prop1</Property1>
    <Property2>Prop2</Property2>
    <Property3>Prop3</Property3>
  </Item>
</Catalog>

I tried many queries, but got syntax errors every time, due to my poor knowledge of XQuery. For example, I tried this query:

xquery version "3.0";
declare copy-namespaces no-preserve, inherit;
declare variable $document external;

declare variable $items := $document/Catalog/Item;

for $item in $items
return
   <Item>
     <Name>{ }</Name>
     { $item/Property1 } 
     { $item/Property2 }
     { $item/Property3 }
   </Item>

...but the resulting XML document (an array of string using the xquery transformation module in anypoint Studio) doesn't contain the root node.

Any help would be greatly appreciated.

2
Please edit your post, and add XQuery that you already tried. - Yitzhak Khabinsky
Which element do you want to insert, where exactly? At least show the XML result you want to create. And if you are new to XQuery perhaps start with a working example of using insert-before before trying to use it with a more complex input and several nodes. If you have tried something, then show the exact code and the exact error you get. - Martin Honnen
Yes, sorry. I'd like to insert the tag <Name> at position 1 in every <Item> node. I edited the post to clarify more my issue. - Marco S

2 Answers

1
votes

You don't need insert-before but

/*!element { node-name() } {
    Item ! element { node-name() } {
        insert-before(*, 1, <Name/>)
    }
}

would be one way to use it, although

/*!element { node-name() } {
    Item ! element { node-name() } {
        <Name/>, *
    }
}

does the job.

Note that XQuery update might be more adequate if your processor supports it (e.g. BaseX).

1
votes

I don't have Mulesoft and its Anypoint Studio.

I am using BaseX v.9.5.1

XQuery

declare context item := document {
<Catalog>
  <Item>
    <Property1>Prop1</Property1>
    <Property2>Prop2</Property2>
    <Property3>Prop3</Property3>
  </Item>
  <Item>
    <Property1>Prop1</Property1>
    <Property2>Prop2</Property2>
    <Property3>Prop3</Property3>
  </Item>
</Catalog>
};

<Catalog>
{
  let $new := <newElement>somevalue</newElement>
  for $x in ./Catalog/Item
  return <Item>
    {$new, $x/*}
  </Item>
  
}
</Catalog>

Output

<Catalog>
  <Item>
    <newElement>somevalue</newElement>
    <Property1>Prop1</Property1>
    <Property2>Prop2</Property2>
    <Property3>Prop3</Property3>
  </Item>
  <Item>
    <newElement>somevalue</newElement>
    <Property1>Prop1</Property1>
    <Property2>Prop2</Property2>
    <Property3>Prop3</Property3>
  </Item>
</Catalog>