Ryan,

This works fine:

let $test := <test><a>hi</a></test>
return mem:node-replace($test/a, <a>there</a>)

=> <test><a>there</a></test>

But if I pluck out a session variable, mem:node-replace has no effect:

(: previously executed
xdmp:set-session-field('test', <test><a>hi</a></test>)
:)

let $test := xdmp:get-session-field('test')
return mem:node-replace($test/a, <a>there</a>)

=> <test><a>hi</a></test>

Why would this work in the first scenario, but not the other? I'm developing some basic CRUD functionality. Say I've got a <user><name>eric</name></user> saved in /eric.xml in the DB. I've got the same user element in my session. To make an update to the nested name element, here's the commonplace workflow:

- POST new name to an xquery script
- script does an xdmp:node-replace(doc('/eric.xml')/user/name, <name>blah</name>), which works fine.
- update session variable to reflect the change

It seems I can't just reload the contents of eric.xml into my session variable, I'm guessing because the change hasn't _really_ taken place yet (due to the transactional nature of each xquery script, nothing is actually changed until after the script has executed, correct?). Instead, I thought I could grab the current user session variable into a local variable, update it in-memory (with the in-mem-update.xqy module), and put the new structure back into the session. This doesn't work, for some reason, as shown above.

The longer I work with xquery, the less feasible it seems to use it in place of an XCC-enabled java-based website. :(

Eric

Ryan Grimm wrote:
Hi Eric,

The xdmp:node-* functions are intended to be used on nodes that are stored in the database, that's why you're getting the error about constructed nodes.

Your work around is fine but I've actually shared a general purpose library for doing exactly what you're looking to do. You can find it on the developer site in the commons area at:

http://xqzone.marklogic.com/svn/commons/trunk/memupdate/

The functions are almost identical to the xdmp:node-* functions except that they return the modified xml back to you which seems like it's exactly what you're looking for. They also allow you to pass in multiple nodes to delete or insert instead of just one. I've included some examples on how to use the library but if you have any questions let me know.

Bonus answer: If the element isn't in a namespace name(<hi/>) will work, otherwise you can use local-name(<x:hi/>) and it will return "hi".

--Ryan


On Sep 15, 2008, at 10:26 AM, Eric Palmitesta wrote:

Hi all,

I'd like a function to add an attribute to an input element and return it. I realize that xquery is functional, and the returned element will be a new element rather than a modified version of the input element, which is fine.

Consider the following function:

---

define function f($x as element(test))
as element(test)
{
 xdmp:node-insert-child($x, attribute new { "new" } )
}

let $x := <test blah="blah">some text</test>
return f($x)

=> Error: Cannot update constructed nodes

---

This errors out and tells me "Cannot update constructed nodes", as indicated in the API docs ("On-the-fly constructed nodes cannot be updated.", http://developer.marklogic.com/pubs/3.2/apidocs/UpdateBuiltins.html#node-insert-child)

Here's a workaround function:

---

define function g($x as element(test))
as element(test)
{
 <test>{
   $x/text(),
   $x/child::*,
   $x/attribute::*,
   attribute new{ "new" }
 }</test>
}

let $x := <test blah="blah">some text</test>
return g($x)

=> <test blah="blah" new="new">some text</test>

---

It works. Is there a better way though? Also, what's the point of xdmp:node-insert-child if it can't operate on an argument to a function? Why is the arg considered 'on-the-fly'? Shouldn't the function not care where $x came from or how it was constructed?

Bonus question: If I have an $x as element(), how can I pull out the element name? IE if $x := <hi />, I want "hi".

Cheers,

Eric
_______________________________________________
General mailing list
[email protected]
http://xqzone.com/mailman/listinfo/general

_______________________________________________
General mailing list
[email protected]
http://xqzone.com/mailman/listinfo/general
_______________________________________________
General mailing list
[email protected]
http://xqzone.com/mailman/listinfo/general

Reply via email to