At 2010-02-16 11:10 -0500, Tony Mariella wrote:
Is there a way to use fn:distinct-nodes

There is no fn:distinct-nodes in the XPath library ... the functions and operators specification has an example of what might be one based on node identity:

http://www.w3.org/TR/2007/REC-xpath-functions-20070123/#func-distinct-nodes-stable

or fn:distinct-values to
return a set of distinct node that are part of the results xml ?
Example:

<results>
    <item>
       <addr>24 Short Rd</addr>
       <city>Baltimore</city>
       <state>MD</state>
       <testVal/>
    </item>
    <item>
       <addr>24 Short Rd</addr>
       <city>Baltimore</city>
       <state>MD</state>
       <testVal/>
    </item>
    <item>
       <addr>24 Short Rd</addr>
       <city>Baltimore</city>
       <state>MD</state>
       <testVal/>
    </item>
    <item>
       <addr>24 Short Rd</addr>
       <city>Baltimore</city>
       <state>MD</state>
       <testVal>TEST1</testVal>
    </item>
</results>
The highlighted xml is what I would want returned.

Then that isn't the "traditional" implementation of "distinct values" ... you would get one for each of the two distinct ones.

Or if all the items are identical, only return a single item.

A special case.

This is a query result so I would not know the results in advance.

Well, first step, to find the distinct <item> elements would be:

T:\ftemp>type tony.xml
<results>
    <item>
       <addr>24 Short Rd</addr>
       <city>Baltimore</city>
       <state>MD</state>
       <testVal/>
    </item>
    <item>
       <addr>24 Short Rd</addr>
       <city>Baltimore</city>
       <state>MD</state>
       <testVal/>
    </item>
    <item>
       <addr>24 Short Rd</addr>
       <city>Baltimore</city>
       <state>MD</state>
       <testVal/>
    </item>
    <item>
       <addr>24 Short Rd</addr>
       <city>Baltimore</city>
       <state>MD</state>
       <testVal>TEST1</testVal>
    </item>
</results>

T:\ftemp>xquery tony.xq
<?xml version="1.0" encoding="UTF-8"?>
<results>
   <item>
       <addr>24 Short Rd</addr>
       <city>Baltimore</city>
       <state>MD</state>
       <testVal/>
    </item>
   <item>
       <addr>24 Short Rd</addr>
       <city>Baltimore</city>
       <state>MD</state>
       <testVal>TEST1</testVal>
    </item>
</results>
T:\ftemp>type tony.xq
declare function local:distinct-nodes ($arg as node()*) as node()*
{
   for $a at $apos in $arg
   let $before_a := fn:subsequence($arg, 1, $apos - 1)
   where every $ba in $before_a satisfies not(deep-equal($ba,$a))
   return $a
};

<results>
  { local:distinct-nodes( doc('tony.xml')/results/item ) }
</results>
T:\ftemp>


.... but that returns the two distinct <item> elements. It sounds like you want the only <item> elements that do not have duplicates:

T:\ftemp>type tony.xml
<results>
    <item>
       <addr>24 Short Rd</addr>
       <city>Baltimore</city>
       <state>MD</state>
       <testVal/>
    </item>
    <item>
       <addr>24 Short Rd</addr>
       <city>Baltimore</city>
       <state>MD</state>
       <testVal/>
    </item>
    <item>
       <addr>24 Short Rd</addr>
       <city>Baltimore</city>
       <state>MD</state>
       <testVal/>
    </item>
    <item>
       <addr>24 Short Rd</addr>
       <city>Baltimore</city>
       <state>MD</state>
       <testVal>TEST1</testVal>
    </item>
</results>

T:\ftemp>xquery tony.xq
<?xml version="1.0" encoding="UTF-8"?>
<results>
   <item>
       <addr>24 Short Rd</addr>
       <city>Baltimore</city>
       <state>MD</state>
       <testVal>TEST1</testVal>
    </item>
</results>
T:\ftemp>type tony.xq
declare function local:distinct-nodes ($arg as node()*) as node()*
{
   for $a at $apos in $arg
   where every $other in $arg except $a satisfies not(deep-equal($other,$a))
   return $a
};

<results>
  { local:distinct-nodes( doc('tony.xml')/results/item ) }
</results>
T:\ftemp>

... but that won't handle your special case of when they are all identical you want one returned, that would be added by using:

T:\ftemp>type tony.xml
<results>
    <item>
       <addr>24 Short Rd</addr>
       <city>Baltimore</city>
       <state>MD</state>
       <testVal/>
    </item>
    <item>
       <addr>24 Short Rd</addr>
       <city>Baltimore</city>
       <state>MD</state>
       <testVal/>
    </item>
    <item>
       <addr>24 Short Rd</addr>
       <city>Baltimore</city>
       <state>MD</state>
       <testVal/>
    </item>
</results>

T:\ftemp>xquery tony.xq
<?xml version="1.0" encoding="UTF-8"?>
<results>
   <item>
       <addr>24 Short Rd</addr>
       <city>Baltimore</city>
       <state>MD</state>
       <testVal/>
    </item>
</results>
T:\ftemp>type tony.xq
declare function local:distinct-nodes ($arg as node()*) as node()*
{
   let $result :=
     for $a at $apos in $arg
     where every $other in $arg except $a satisfies not(deep-equal($other,$a))
     return $a
   return if( count($result) = 0 ) then $arg[1] else $result
};

<results>
  { local:distinct-nodes( doc('tony.xml')/results/item ) }
</results>
T:\ftemp>

I hope this helps. Though I wonder if you've expressed your requirement accurately, as it seems incongruous with your use of terminology. Note also that the execution time could be significant if you have a lot of items or they are deep items.

. . . . . . . . Ken

p.s. only two seats still remain for the XQuery/XSLT training in Prague next month


--
XSLT/XQuery/XPath training after http://XMLPrague.cz 2010-03-15/19
XSLT/XQuery/XPath training:   San Carlos, California 2010-04-26/30
Vote for your XML training:   http://www.CraneSoftwrights.com/q/i/
Crane Softwrights Ltd.          http://www.CraneSoftwrights.com/q/
Training tools: Comprehensive interactive XSLT/XPath 1.0/2.0 video
Video lesson:    http://www.youtube.com/watch?v=PrNjJCh7Ppg&fmt=18
Video overview:  http://www.youtube.com/watch?v=VTiodiij6gE&fmt=18
G. Ken Holman                 mailto:[email protected]
Male Cancer Awareness Nov'07  http://www.CraneSoftwrights.com/q/bc
Legal business disclaimers:  http://www.CraneSoftwrights.com/legal

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

Reply via email to