[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 Error

Kevin Grover kevin at kevingrover.net
Tue Feb 26 18:38:10 PST 2008


  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> 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
> ________________________________________
> From: David Carlisle [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
> 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
-------------- next part --------------
An HTML attachment was scrubbed...
URL: http://x-query.com/pipermail/talk/attachments/20080226/c78ad75c/attachment.htm


Purchase Stylus Studio Online Today!

Purchasing Stylus Studio from our online shop is Easy, Secure and Value Priced!

Buy Stylus Studio Now

Download The World's Best XML IDE!

Accelerate XML development with our award-winning XML IDE - Download a free trial today!

Don't miss another message! Subscribe to this list today.
Email
First Name
Last Name
Company
Subscribe in XML format
RSS 2.0
Atom 0.3
Site Map | Privacy Policy | Terms of Use | Trademarks
Free Stylus Studio XML Training:
W3C Member
Stylus Studio® and DataDirect XQuery™are products from DataDirect Technologies, is a registered trademark of Progress Software Corporation, in the U.S. and other countries. © 2004-2007 All Rights Reserved.