|
[XQuery Talk Mailing List Archive Home] [By Date] [By Thread] [By Subject] [By Author] [Recent Entries] [Reply To This Message] Function and Query Evaluation with No XML Tags ErrorWei, Alice J. ajwei at indiana.eduWed Feb 27 05:41:49 PST 2008
Hi, Kevin:
Thanks, this does bring some help to what I am trying to work on now. To certain extent, I have this feeling that the syntax between XQuery functions and XQuery user-defined functions are somewhat different.
Your code does point out quite a few different options and the variety of errors I could be getting when I am not doing them correctly. It does do the trick.
Thanks for your help.
Alice
======================================================
Alice Wei
MIS 2008
School of Library and Information Science
Indiana University Bloomington
http://x-query.com/mailman/listinfo/talk
________________________________________
From: http://x-query.com/mailman/listinfo/talk [http://x-query.com/mailman/listinfo/talk] On Behalf Of Kevin Grover [http://x-query.com/mailman/listinfo/talk]
Sent: Tuesday, February 26, 2008 9:38 PM
To: Wei, Alice J.
Cc: http://x-query.com/mailman/listinfo/talk
Subject: Re: Function and Query Evaluation with No XML Tags Error
On Tue, Feb 26, 2008 at 8:21 AM, Wei, Alice J. <http://x-query.com/mailman/listinfo/talk<mailto:http://x-query.com/mailman/listinfo/talk>> wrote:
Hi, David:
I think I am having a different issue different from what I had several weeks ago.
What I have modified is from:
let $ad := fn:collection("xmldb:exist://db/cbml")//ad/p[contains(upper-case(.), 'BOOK')]
let $sorted_result:=
for $doc in distinct-values($ad)
order by $doc
return $doc
for $r at $count in $sorted_result
let $nodes := $ad[. = $r][1]
return
<ad>
{$nodes}
</ad>
by trying to put it in user-defined functions, which is currently giving me quite a bit of problems from itself.
declare boundary-space preserve;
declare function local:distinct(
$seq as xs:anyAtomicType*)
as xs:anyAtomicType
{
let $doc := distinct-values($seq)
order by $doc
return
<ad>{$doc} </ad>
};
for $ad in
distinct-values(collection("xmldb:exist://db/cbml")//ad/p[contains(upper-case(.$
return
<ad>{local:distinct($ad)}</ad>
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.
Is this possible?
Thanks for your help.
======================================================
Alice Wei
MIS 2008
School of Library and Information Science
Indiana University Bloomington
http://x-query.com/mailman/listinfo/talk<mailto:http://x-query.com/mailman/listinfo/talk>
________________________________________
From: David Carlisle [http://x-query.com/mailman/listinfo/talk<mailto:http://x-query.com/mailman/listinfo/talk>]
Sent: Tuesday, February 26, 2008 10:33 AM
To: Wei, Alice J.
Cc: http://x-query.com/mailman/listinfo/talk<mailto:http://x-query.com/mailman/listinfo/talk>
Subject: Re: Function and Query Evaluation with No XML Tags Error
Alice,
Alice it seems hard to help as you have been essentially posting the
same code, with the same error for weeks,
When you go
for $ad in distinct-values(...anything)
then, on each iteration $ad will be a single string (one of the values)
So on each call to local:distinct($ad) you are passing in a single string. so
doing operations such as distinct-values() or for or order by are all
essentialy null-operations. It's not an error to take all the
unique values from a sequence of length one and then sort them, but you will always
just get back the value you started with.
See for example:
/xquerytalk/2008-January/002436.html
David
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).
Example XML file:
<?xml version="1.0"?>
<data>
<record>
<name>Fred Flinstone</name>
<street>Fred's Street</street>
</record>
<record>
<name>Fred Flinstone</name>
<street>Fred's Street</street>
</record>
<record>
<name>Barney Rubble</name>
<street>Barney's Street</street>
</record>
<record>
<name>Wilma Flinstone</name>
<street>Wilma's Street</street>
</record>
<record>
<name>Betty Rubble</name>
<street>Betty's Street</street>
</record>
</data>
NOTICE: Fred's entry is duplicated!
Example Query:
for $r in distinct-values(/data/record)
return $r
Results:
<?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
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.
It's like this:
for $r in /data/record
return string($r)
Results:
<?xml version="1.0" encoding="UTF-8"?>
Fred Flinstone
Fred's Street
Fred Flinstone
Fred's Street
Barney Rubble
Barney's Street
Wilma Flinstone
Wilma's Street
Betty Rubble
Betty's Street
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.
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.
I figured I could use this:
(: ** Generates runtime errror ** :)
for $r in /data/record[not(string(.)=string(preceding::*))]
return string($r)
But it generates a complaint (at runtime):
Description: A sequence of more than one item is not allowed as the first argument of string() (<record/>, <name/>, ...)
** SEE More at the bottom: I figured it out.
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.
Try removing the disctinct-values (and iterate over the elements) and you may get something closer to what you are expecting.
** (corrected from above)
Here's a unique by value
for $r in /data/record[not(string(.)=string((preceding-sibling::*)[1]))]
return string($r)
Results:
<?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
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:
for $r in /data/record[not(string(.)=string((preceding-sibling::*)[1]))]
return normalize-space($r)
Results:
<?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
NOTICES: it all a string (because normalize-space converts things to string) but 'extra' whitespace is stripped.
Or:
for $r in /data/record[not(string(.)=string((preceding-sibling::*)[1]))]
return <newelement>{normalize-space($r)}</newelement>
Results:
<?xml version="1.0" encoding="UTF-8"?>
<newelement>Fred Flinstone Fred's Street</newelement>
<newelement>Barney Rubble Barney's Street</newelement>
<newelement>Wilma Flinstone Wilma's Street</newelement>
<newelement>Betty Rubble Betty's Street</newelement>
NOTICE: String results wrapped in a new tag.
Or:
for $r in /data/record[not(string(.)=string((preceding-sibling::*)[1]))]
return <newelement>{$r}</newelement>
Results:
<?xml version="1.0" encoding="UTF-8"?>
<newelement>
<record>
<name>Fred Flinstone</name>
<street>Fred's Street</street>
</record>
</newelement>
<newelement>
<record>
<name>Barney Rubble</name>
<street>Barney's Street</street>
</record>
</newelement>
<newelement>
<record>
<name>Wilma Flinstone</name>
<street>Wilma's Street</street>
</record>
</newelement>
<newelement>
<record>
<name>Betty Rubble</name>
<street>Betty's Street</street>
</record>
</newelement>
NOTICE: Original XML elements (and sub elements) wrapped in a new tag.
Or, if you plan on using that 'logic' over and over, you can create a function for it:
XQuery: This is the same as (functionally) the previous example, it just defines (and uses) a local function
declare function local:unique-nodes-by-value($seq as element()*) as element()*
{
for $r in $seq[not(string(.)=string((preceding-sibling::*)[1]))]
return $r
};
for $r in local:unique-nodes-by-value(/data/record)
return <newelement>{$r}</newelement>
Using XPaths, you can pick and choose what element/sub element (values, content, or sub-content) you get.
I hope this helps some.
Keep in mind, I'm relatively new at this so there are probably better ways.
- Kevin
|
PURCHASE STYLUS STUDIO ONLINE TODAY!Purchasing Stylus Studio from our online shop is Easy, Secure and Value Priced! Download The World's Best XML IDE!Accelerate XML development with our award-winning XML IDE - Download a free trial today! Subscribe in XML format
|






