Discussion:
[xquery-talk] XQuery 3 try/catch and duplicate attributes
David Sewell
2013-12-19 18:21:08 UTC
Permalink
I'm trying to clean up some old code of ours that is throwing server errors when
fed buggy data. To simplify greatly, the code is something like this:

let $element := <el att1="one" att2="two">text</el>
return element new {
$element/attribute(),
attribute id { "new-id" },
$element/node()
}

where the content of $element comes from XML data where <el> is not supposed to
carry an @id attribute. Of course if the data is buggy and $element has a child
@id, the above code throws a dynamic error (XQDY0025, duplicate attribute
names).

I naively thought this might be a quick fix to prevent runtime errors:

xquery version "3.0";
let $element := <el att1="one" att2="two" id="old-id">text</el>
return element new {
$element/attribute(),
try {attribute id { "new-id" }} catch * {()},
$element/node()
}

but it doesn't trap the error (in any XQuery 3 processor I've checked). The
try/catch will work only if put around the entire element constructor.

Can someone who understands the 3.0 spec better than I do explain the general
principle behind this? Is it that the processor cannot be expected to evaluate
the legality of the constructed element until all its parts have been assembled?

David
--
David Sewell, Editorial and Technical Manager
ROTUNDA, The University of Virginia Press
PO Box 400314, Charlottesville, VA 22904-4314 USA
Email: ***@virginia.edu Tel: +1 434 924 9973
Web: http://rotunda.upress.virginia.edu/
Christian Grün
2013-12-19 18:31:10 UTC
Permalink
Hi David,
Post by David Sewell
[…]
try {attribute id { "new-id" }} catch * {()},
[…]
but it doesn't trap the error (in any XQuery 3 processor I've checked). The
try/catch will work only if put around the entire element constructor.
The reason for this is that the attribute constructor itself is
correct. The error occurs when trying to add the newly created
attribute to the element.

The following query should work:

let $element := <el att1="one" att2="two" id="old-id">text</el>
return element new {
$element/attribute(),
if($element/@id) then () else attribute id { "new-id" },
$element/node()
}

Hope this helps,
Christian
Ryan Dew
2013-12-19 18:41:33 UTC
Permalink
Adding to this, my personal opinion is that try/catches should be a last
resort and you'll be a better programmer for avoiding them. Not to mention,
you can often see performance increases by avoiding them if the code is
something that is called repeatedly and are less likely to unintentionally
mask problems. For example you can do the following (please excuse the
formatting):

xquery version "3.0";
let $element := <el att1="one" att2="two" id="old-id">text</el>
return element new {
$element/attribute(),
if (fn:empty($element/@id)) then attribute id { "new-id" } else (),
$element/node()
}



On Thu, Dec 19, 2013 at 11:31 AM, Christian Grün
Post by Christian Grün
Hi David,
Post by David Sewell
[…]
try {attribute id { "new-id" }} catch * {()},
[…]
but it doesn't trap the error (in any XQuery 3 processor I've checked).
The
Post by David Sewell
try/catch will work only if put around the entire element constructor.
The reason for this is that the attribute constructor itself is
correct. The error occurs when trying to add the newly created
attribute to the element.
let $element := <el att1="one" att2="two" id="old-id">text</el>
return element new {
$element/attribute(),
$element/node()
}
Hope this helps,
Christian
_______________________________________________
http://x-query.com/mailman/listinfo/talk
David Sewell
2013-12-19 19:23:07 UTC
Permalink
Thanks. As I say, I'm cleaning up legacy code that has a lot of mess in it, and
in fact a try/catch isn't the solution I'll be using to avoid the problem in
this case; I was just curious about the (in)ability of try/catch to prevent
duplicate attributes within an element constructor. Clearly there are better
ways to prevent them than relying on that.

David
Post by Ryan Dew
Adding to this, my personal opinion is that try/catches should be a last
resort and you'll be a better programmer for avoiding them. Not to mention,
you can often see performance increases by avoiding them if the code is
something that is called repeatedly and are less likely to unintentionally
mask problems. For example you can do the following (please excuse the
xquery version "3.0";
let $element := <el att1="one" att2="two" id="old-id">text</el>
return element new {
$element/attribute(),
$element/node()
}
On Thu, Dec 19, 2013 at 11:31 AM, Christian GrÃŒn
Post by Christian Grün
Hi David,
Post by David Sewell
[
]
try {attribute id { "new-id" }} catch * {()},
[
]
but it doesn't trap the error (in any XQuery 3 processor I've checked).
The
Post by David Sewell
try/catch will work only if put around the entire element constructor.
The reason for this is that the attribute constructor itself is
correct. The error occurs when trying to add the newly created
attribute to the element.
let $element := <el att1="one" att2="two" id="old-id">text</el>
return element new {
$element/attribute(),
$element/node()
}
Hope this helps,
Christian
_______________________________________________
http://x-query.com/mailman/listinfo/talk
--
David Sewell, Editorial and Technical Manager
ROTUNDA, The University of Virginia Press
PO Box 400314, Charlottesville, VA 22904-4314 USA
Email: ***@virginia.edu Tel: +1 434 924 9973
Web: http://rotunda.upress.virginia.edu/
Loading...