<br><div class="gmail_quote">On Tue, Feb 26, 2008 at 8:21 AM, Wei, Alice J. <<a href="mailto:ajwei@indiana.edu">ajwei@indiana.edu</a>> wrote:<br><blockquote class="gmail_quote" style="border-left: 1px solid rgb(204, 204, 204); margin: 0pt 0pt 0pt 0.8ex; padding-left: 1ex;">
Hi, David:<br>
<br>
I think I am having a different issue different from what I had several weeks ago.<br>
What I have modified is from:<br>
<br>
let $ad := fn:collection("xmldb:exist://db/cbml")//ad/p[contains(upper-case(.), 'BOOK')]<br>
let $sorted_result:=<br>
for $doc in distinct-values($ad)<br>
order by $doc<br>
return $doc<br>
for $r at $count in $sorted_result<br>
let $nodes := $ad[. = $r][1]<br>
return<br>
<ad><br>
{$nodes}<br>
</ad><br></blockquote><blockquote class="gmail_quote" style="border-left: 1px solid rgb(204, 204, 204); margin: 0pt 0pt 0pt 0.8ex; padding-left: 1ex;">
<br>
by trying to put it in user-defined functions, which is currently giving me quite a bit of problems from itself.<br>
<div class="Ih2E3d"><br>
declare boundary-space preserve;<br>
declare function local:distinct(<br>
$seq as xs:anyAtomicType*)<br>
as xs:anyAtomicType<br>
{<br>
</div> let $doc := distinct-values($seq)<br>
<div class="Ih2E3d"> order by $doc<br>
return<br>
<ad>{$doc} </ad><br>
};<br>
<br>
</div> for $ad in<br>
distinct-values(collection("xmldb:exist://db/cbml")//ad/p[contains(upper-case(.$<br>
<div class="Ih2E3d"> return<br>
<ad>{local:distinct($ad)}</ad><br>
<br>
</div>As I mentioned before, I only intend to have the output be appeared in the same way as the above XQuery that is not in the function.<br>
Is this possible?<br>
<br>
Thanks for your help.<br>
<div class="Ih2E3d">======================================================<br>
Alice Wei<br>
MIS 2008<br>
School of Library and Information Science<br>
Indiana University Bloomington<br>
<a href="mailto:ajwei@indiana.edu">ajwei@indiana.edu</a><br>
________________________________________<br>
</div>From: David Carlisle [<a href="mailto:davidc@nag.co.uk">davidc@nag.co.uk</a>]<br>
Sent: Tuesday, February 26, 2008 10:33 AM<br>
To: Wei, Alice J.<br>
Cc: <a href="mailto:talk@x-query.com">talk@x-query.com</a><br>
Subject: Re: [xquery-talk] Function and Query Evaluation with No XML Tags Error<br>
<div><div></div><div class="Wj3C7c"><br>
Alice,<br>
<br>
Alice it seems hard to help as you have been essentially posting the<br>
same code, with the same error for weeks,<br>
<br>
When you go<br>
<br>
for $ad in distinct-values(...anything)<br>
<br>
then, on each iteration $ad will be a single string (one of the values)<br>
<br>
So on each call to local:distinct($ad) you are passing in a single string. so<br>
doing operations such as distinct-values() or for or order by are all<br>
essentialy null-operations. It's not an error to take all the<br>
unique values from a sequence of length one and then sort them, but you will always<br>
just get back the value you started with.<br>
<br>
<br>
See for example:<br>
<br>
<a href="http://x-query.com/pipermail/talk/2008-January/002436.html" target="_blank">http://x-query.com/pipermail/talk/2008-January/002436.html</a><br>
<br>
David<br>
<br></div></div></blockquote></div><br>
distinct-values returns a list of values (strings) NOT elements.
(hence the 'values'). It's throwing away all of the XML element markup and just
keeping the string values (all smashed together).<br>
<br>Example XML file:<br><?xml version="1.0"?><br><data><br> <record><br> <name>Fred Flinstone</name><br> <street>Fred's Street</street><br> </record><br>
<record><br> <name>Fred Flinstone</name><br> <street>Fred's Street</street><br> </record><br> <record><br> <name>Barney Rubble</name><br> <street>Barney's Street</street><br>
</record><br> <record><br> <name>Wilma Flinstone</name><br> <street>Wilma's Street</street><br> </record><br> <record><br> <name>Betty Rubble</name><br>
<street>Betty's Street</street><br> </record><br></data><br><br>NOTICE: Fred's entry is duplicated!<br><br>Example Query:<br>for $r in distinct-values(/data/record)<br>return $r<br><br>
<br>Results:<br><?xml version="1.0" encoding="UTF-8"?><br> Fred Flinstone<br> Fred's Street<br> <br> Barney Rubble<br> Barney's Street<br> <br> Wilma Flinstone<br> Wilma's Street<br>
<br> Betty Rubble<br> Betty's Street<br> <br>NOTICE: No XML markup. It was all stripped. It's like calling string on it: <record><name> and <street> have been removed: the data flattened into a string.<br>
<br>It's like this:<br><br>for $r in /data/record<br>return string($r)<br><br><br>Results:<br><?xml version="1.0" encoding="UTF-8"?><br> Fred Flinstone<br> Fred's Street<br> <br> Fred Flinstone<br>
Fred's Street<br> <br> Barney Rubble<br> Barney's Street<br> <br> Wilma Flinstone<br> Wilma's Street<br> <br> Betty Rubble<br> Betty's Street<br> <br>Again: no XML markup. They're strings (because I explicitly converted them to strings). However, this time, I DID get the duplicated entry for Fred.<br>
<br>Will you really have different nodes (with subnodes) that contain completely duplicated data? If so, I have no suggestions. If not and you're really getting multiple instances of the SAME node, then use the id function to test for uniqueness.<br>
<br>I figured I could use this:<br>(: ** Generates runtime errror ** :)<br>for $r in /data/record[not(string(.)=string(preceding::*))]<br>return string($r)<br><br>But it generates a complaint (at runtime): <br>Description: A sequence of more than one item is not allowed as the first argument of string() (<record/>, <name/>, ...) <br>
** SEE More at the bottom: I figured it out.<br><br>I tried a few other things to get distinct nodes based on the content, but none of the others would even parse : I'm still mostly in the dark about the magic of XQuery and XPath.<br>
<br>Try removing the disctinct-values (and iterate over the elements) and you may get something closer to what you are expecting.<br><br>** (corrected from above)<br>Here's a unique by value<br>for $r in /data/record[not(string(.)=string((preceding-sibling::*)[1]))]<br>
return string($r)<br><br>Results:<br><?xml version="1.0" encoding="UTF-8"?><br> Fred Flinstone<br> Fred's Street<br> <br> Barney Rubble<br> Barney's Street<br> <br> Wilma Flinstone<br>
Wilma's Street<br> <br> Betty Rubble<br> Betty's Street<br> <br>Again. It's unique (because I made it unique in the XPath), but it's iterating over the nodes. It's a string, because I explicitly convert them to strings. I could have also done:<br>
<br>for $r in /data/record[not(string(.)=string((preceding-sibling::*)[1]))]<br>return normalize-space($r)<br><br><br>Results:<br><?xml version="1.0" encoding="UTF-8"?>Fred Flinstone Fred's Street Barney Rubble Barney's Street Wilma Flinstone Wilma's Street Betty Rubble Betty's Street<br>
<br>NOTICES: it all a string (because normalize-space converts things to string) but 'extra' whitespace is stripped.<br><br>Or:<br>for $r in /data/record[not(string(.)=string((preceding-sibling::*)[1]))]<br>return <newelement>{normalize-space($r)}</newelement><br>
<br>Results:<br><?xml version="1.0" encoding="UTF-8"?><br><newelement>Fred Flinstone Fred's Street</newelement><br><newelement>Barney Rubble Barney's Street</newelement><br>
<newelement>Wilma Flinstone Wilma's Street</newelement><br><newelement>Betty Rubble Betty's Street</newelement><br><br>NOTICE: String results wrapped in a new tag.<br><br>Or:<br>for $r in /data/record[not(string(.)=string((preceding-sibling::*)[1]))]<br>
return <newelement>{$r}</newelement><br><br>Results:<br><?xml version="1.0" encoding="UTF-8"?><br><newelement><br> <record><br> <name>Fred Flinstone</name><br>
<street>Fred's Street</street><br> </record><br></newelement><br><newelement><br> <record><br> <name>Barney Rubble</name><br> <street>Barney's Street</street><br>
</record><br></newelement><br><newelement><br> <record><br> <name>Wilma Flinstone</name><br> <street>Wilma's Street</street><br> </record><br></newelement><br>
<newelement><br> <record><br> <name>Betty Rubble</name><br> <street>Betty's Street</street><br> </record><br></newelement><br><br>NOTICE: Original XML elements (and sub elements) wrapped in a new tag.<br>
<br>Or, if you plan on using that 'logic' over and over, you can create a function for it:<br><br>XQuery: This is the same as (functionally) the previous example, it just defines (and uses) a local function<br><br>
declare function local:unique-nodes-by-value($seq as element()*) as element()*<br>{<br> for $r in $seq[not(string(.)=string((preceding-sibling::*)[1]))]<br> return $r<br>};<br><br>for $r in local:unique-nodes-by-value(/data/record)<br>
return <newelement>{$r}</newelement><br><br>Using XPaths, you can pick and choose what element/sub element (values, content, or sub-content) you get.<br><br>I hope this helps some.<br><br>Keep in mind, I'm relatively new at this so there are probably better ways.<br>
<br>- Kevin<br><br>