joewiz
12/27/2015 - 7:34 PM

EXPath Facet Spec workbook

EXPath Facet Spec workbook

<exception>
    <path>/db/apps/facet/case-3.xq</path>
    <message>
        err:XPTY0004 Grouping variable g evaluates to more than one item [at line 164, column 5, source: /db/apps/facet/case-3.xq] 
        In function: facet:count(item()*, element()*) [164:5:/db/apps/facet/case-3.xq]
    </message>
</exception>
xquery version "3.0";

(:~  An implementation of facet:count as described in "Case 3: Counting facets when the grouping key consists of more than 1 value" 
    of the EXPath Facet Spec. Depends on eXist's util:eval() function to handle dynamic path expressions.
    
    Fails with err:XPTY0004, as predicted by the spec: "There is no equivalent XQuery using group-by-clause, because skill is 
    a repeatable element. Following XQuery will throw err:XPTY0004."

    @see http://expath.org/spec/facet/20151225#case-3-counting-facets-when-the-grouping-key-consists-of-more-than-1-value
:)

import module namespace util="http://exist-db.org/xquery/util";

declare namespace facet = "http://expath.org/ns/facet";

declare function facet:count($results as item()*, $facet-definitions as element(facet:facet-definition)*) as element(facet:facets) {
    <facet:facets>
        <facet:facet name="{$facet-definitions/@name}">
            {
                for $r in $results
                let $group-by-expression := concat('$r/', $facet-definitions/facet:group-by/facet:sub-path)
                (: use util:eval() for dynamic evaluation of arbitrary paths in eXist :)
                group by $g := util:eval($group-by-expression)
                order by count($r) descending
                return 
                    <facet:key value="{ $g }" count="{ count($r) }"/>
            }
        </facet:facet>
    </facet:facets>
};

let $sample :=
    <sample>
        <employee>
            <name>John Doe</name>
            <sex>Male</sex>
            <organization>HR</organization>
            <location>
                <country>US</country>
                <state>CA</state>
                <city>Pleasanton</city>
                <gps>
                    <longitude>-95.677068</longitude>
                    <latitude>37.0625</latitude>
                </gps>
            </location>
            <age>21</age>
            <employDate>2010-02-01</employDate>
            <skills>
                <skill>Word</skill>
                <skill>Excel</skill>
                <skill>Windows</skill>
            </skills>
        </employee>
        <employee>
            <name>Jane Joe</name>
            <sex>Female</sex>
            <organization>Finance</organization>
            <location>
                <country>US</country>
                <state>CA</state>
                <city>San Francisco</city>
                <gps>
                    <longitude>-122.419416</longitude>
                    <latitude>37.77493</latitude>
                </gps>
            </location>
            <age>18</age>
            <employDate>2003-02-01</employDate>
            <skills>
                <skill>Word</skill>
                <skill>Excel</skill>
                <skill>PowerPoint</skill>
                <skill>Linux</skill>
            </skills>
        </employee>
        <employee>
            <name>Steve</name>
            <sex>Male</sex>
            <organization>HR</organization>
            <location>
                <country>US</country>
                <state>WA</state>
                <city>Seattle</city>
                <gps>
                    <longitude>-122.332071</longitude>
                    <latitude>47.60621</latitude>
                </gps>
            </location>
            <age>31</age>
            <employDate>2010-04-01</employDate>
            <skills>
                <skill>OpenOffice</skill>
                <skill>Word</skill>
            </skills>
        </employee>
        <employee>
            <name>Kylie</name>
            <sex>Female</sex>
            <organization>Sales</organization>
            <location>
                <country>US</country>
                <state>WA</state>
                <city>Bellingham</city>
                <gps>
                    <longitude>-122.488225</longitude>
                    <latitude>48.759553</latitude>
                </gps>
            </location>
            <age>23</age>
            <employDate>2010-06-01</employDate>
            <skills>
                <skill>Word</skill>
                <skill>PowerPoint</skill>
            </skills>
        </employee>
        <employee>
            <name>Kyle</name>
            <sex>Male</sex>
            <organization>Sales</organization>
            <location>
                <country>US</country>
                <state>WA</state>
                <city>Bellingham</city>
                <gps>
                    <longitude>-122.499225</longitude>
                    <latitude>48.759553</latitude>
                </gps>
            </location>
            <age>45</age>
            <employDate>2009-06-01</employDate>
            <skills>
                <skill>PowerPoint</skill>
                <skill>PhotoShop</skill>
            </skills>
        </employee>
        <employee>
            <name>Mike</name>
            <sex>Male</sex>
            <organization>Sales</organization>
            <location>
                <country>US</country>
                <state>OR</state>
                <city>Eugene</city>
                <gps>
                    <longitude>-123.086754</longitude>
                    <latitude>44.052069</latitude>
                </gps>
            </location>
            <age>55</age>
            <employDate>1999-06-01</employDate>
            <skills>
                <skill>PowerPoint</skill>
                <skill>Negotiation</skill>
            </skills>
        </employee>
    </sample>

let $employees := $sample/employee
let $facetDefinition :=
    <facet:facet-definition name="Skill">
        <facet:group-by>
            <facet:sub-path>skills/skill</facet:sub-path>
        </facet:group-by>
    </facet:facet-definition>
return
    facet:count($employees, $facetDefinition)
<facet:facets xmlns:facet="http://expath.org/ns/facet">
    <facet:facet name="Org">
        <facet:key value="Sales and Finance" count="4"/>
        <facet:key value="Other departments" count="2"/>
    </facet:facet>
</facet:facets>
xquery version "3.0";

(:~  An implementation of facet:count as described in "Case 2: Simple customized facet based on group-by function" 
    of the EXPath Facet Spec. Depends on eXist's util:eval() function to handle dynamic path expressions.

    @see http://expath.org/spec/facet/20151225#case-2-simple-customized-facet-based-on-group-by-function
:)

import module namespace util="http://exist-db.org/xquery/util";

declare namespace facet = "http://expath.org/ns/facet";

declare function facet:count($results as item()*, $facet-definitions as element(facet:facet-definition)*) as element(facet:facets) {
    <facet:facets>
        <facet:facet name="{$facet-definitions/@name}">
            {
                for $r in $results
                let $group-by-expression := 
                    if ($facet-definitions/facet:group-by/@function) then
                        concat($facet-definitions/facet:group-by/@function, '($r/', $facet-definitions/facet:group-by/facet:sub-path, ')')
                    else
                        concat('$r/', $facet-definitions/facet:group-by/facet:sub-path)
                (: use util:eval() for dynamic evaluation of arbitrary paths in eXist :)
                group by $g := util:eval($group-by-expression)
                order by count($r) descending
                return 
                    <facet:key value="{ $g }" count="{ count($r) }"/>
            }
        </facet:facet>
    </facet:facets>
};

declare function local:group-by-org($org as xs:string) {
    if ($org = ('Sales', 'Finance')) then 
        'Sales and Finance'
    else 
        'Other departments'
};

let $sample :=
    <sample>
        <employee>
            <name>John Doe</name>
            <sex>Male</sex>
            <organization>HR</organization>
            <location>
                <country>US</country>
                <state>CA</state>
                <city>Pleasanton</city>
                <gps>
                    <longitude>-95.677068</longitude>
                    <latitude>37.0625</latitude>
                </gps>
            </location>
            <age>21</age>
            <employDate>2010-02-01</employDate>
            <skills>
                <skill>Word</skill>
                <skill>Excel</skill>
                <skill>Windows</skill>
            </skills>
        </employee>
        <employee>
            <name>Jane Joe</name>
            <sex>Female</sex>
            <organization>Finance</organization>
            <location>
                <country>US</country>
                <state>CA</state>
                <city>San Francisco</city>
                <gps>
                    <longitude>-122.419416</longitude>
                    <latitude>37.77493</latitude>
                </gps>
            </location>
            <age>18</age>
            <employDate>2003-02-01</employDate>
            <skills>
                <skill>Word</skill>
                <skill>Excel</skill>
                <skill>PowerPoint</skill>
                <skill>Linux</skill>
            </skills>
        </employee>
        <employee>
            <name>Steve</name>
            <sex>Male</sex>
            <organization>HR</organization>
            <location>
                <country>US</country>
                <state>WA</state>
                <city>Seattle</city>
                <gps>
                    <longitude>-122.332071</longitude>
                    <latitude>47.60621</latitude>
                </gps>
            </location>
            <age>31</age>
            <employDate>2010-04-01</employDate>
            <skills>
                <skill>OpenOffice</skill>
                <skill>Word</skill>
            </skills>
        </employee>
        <employee>
            <name>Kylie</name>
            <sex>Female</sex>
            <organization>Sales</organization>
            <location>
                <country>US</country>
                <state>WA</state>
                <city>Bellingham</city>
                <gps>
                    <longitude>-122.488225</longitude>
                    <latitude>48.759553</latitude>
                </gps>
            </location>
            <age>23</age>
            <employDate>2010-06-01</employDate>
            <skills>
                <skill>Word</skill>
                <skill>PowerPoint</skill>
            </skills>
        </employee>
        <employee>
            <name>Kyle</name>
            <sex>Male</sex>
            <organization>Sales</organization>
            <location>
                <country>US</country>
                <state>WA</state>
                <city>Bellingham</city>
                <gps>
                    <longitude>-122.499225</longitude>
                    <latitude>48.759553</latitude>
                </gps>
            </location>
            <age>45</age>
            <employDate>2009-06-01</employDate>
            <skills>
                <skill>PowerPoint</skill>
                <skill>PhotoShop</skill>
            </skills>
        </employee>
        <employee>
            <name>Mike</name>
            <sex>Male</sex>
            <organization>Sales</organization>
            <location>
                <country>US</country>
                <state>OR</state>
                <city>Eugene</city>
                <gps>
                    <longitude>-123.086754</longitude>
                    <latitude>44.052069</latitude>
                </gps>
            </location>
            <age>55</age>
            <employDate>1999-06-01</employDate>
            <skills>
                <skill>PowerPoint</skill>
                <skill>Negotiation</skill>
            </skills>
        </employee>
    </sample>

let $employees := $sample/employee
let $facetDefinition :=
    <facet:facet-definition name="Org">
        <facet:group-by function="local:group-by-org">
            <facet:sub-path>organization</facet:sub-path>
        </facet:group-by>
    </facet:facet-definition>
return
    facet:count($employees, $facetDefinition)
<facet:facets xmlns:facet="http://expath.org/ns/facet">
    <facet:facet name="Org">
        <facet:key value="Sales" count="3"/>
        <facet:key value="HR" count="2"/>
        <facet:key value="Finance" count="1"/>
    </facet:facet>
</facet:facets>
xquery version "3.0";

(:~  An implementation of facet:count as described in "Case 1: Simple facet based on existing attribute" 
    of the EXPath Facet Spec. Depends on eXist's util:eval() function to handle dynamic path expressions.

    @see http://expath.org/spec/facet/20151225#case-1-simple-facet-based-on-existing-attribute 
:)

import module namespace util="http://exist-db.org/xquery/util";

declare namespace facet = "http://expath.org/ns/facet";

declare function facet:count($results as item()*, $facet-definitions as element(facet:facet-definition)*) as element(facet:facets) {
    <facet:facets>
        <facet:facet name="{$facet-definitions/@name}">
            {
                for $r in $results
                let $group-by-expression := concat('$r/', $facet-definitions/facet:group-by/facet:sub-path)
                (: use util:eval() for dynamic evaluation of arbitrary paths in eXist :)
                group by $g := util:eval($group-by-expression)
                order by count($r) descending
                return 
                    <facet:key value="{ $g }" count="{ count($r) }"/>
            }
        </facet:facet>
    </facet:facets>
};

let $sample :=
    <sample>
        <employee>
            <name>John Doe</name>
            <sex>Male</sex>
            <organization>HR</organization>
            <location>
                <country>US</country>
                <state>CA</state>
                <city>Pleasanton</city>
                <gps>
                    <longitude>-95.677068</longitude>
                    <latitude>37.0625</latitude>
                </gps>
            </location>
            <age>21</age>
            <employDate>2010-02-01</employDate>
            <skills>
                <skill>Word</skill>
                <skill>Excel</skill>
                <skill>Windows</skill>
            </skills>
        </employee>
        <employee>
            <name>Jane Joe</name>
            <sex>Female</sex>
            <organization>Finance</organization>
            <location>
                <country>US</country>
                <state>CA</state>
                <city>San Francisco</city>
                <gps>
                    <longitude>-122.419416</longitude>
                    <latitude>37.77493</latitude>
                </gps>
            </location>
            <age>18</age>
            <employDate>2003-02-01</employDate>
            <skills>
                <skill>Word</skill>
                <skill>Excel</skill>
                <skill>PowerPoint</skill>
                <skill>Linux</skill>
            </skills>
        </employee>
        <employee>
            <name>Steve</name>
            <sex>Male</sex>
            <organization>HR</organization>
            <location>
                <country>US</country>
                <state>WA</state>
                <city>Seattle</city>
                <gps>
                    <longitude>-122.332071</longitude>
                    <latitude>47.60621</latitude>
                </gps>
            </location>
            <age>31</age>
            <employDate>2010-04-01</employDate>
            <skills>
                <skill>OpenOffice</skill>
                <skill>Word</skill>
            </skills>
        </employee>
        <employee>
            <name>Kylie</name>
            <sex>Female</sex>
            <organization>Sales</organization>
            <location>
                <country>US</country>
                <state>WA</state>
                <city>Bellingham</city>
                <gps>
                    <longitude>-122.488225</longitude>
                    <latitude>48.759553</latitude>
                </gps>
            </location>
            <age>23</age>
            <employDate>2010-06-01</employDate>
            <skills>
                <skill>Word</skill>
                <skill>PowerPoint</skill>
            </skills>
        </employee>
        <employee>
            <name>Kyle</name>
            <sex>Male</sex>
            <organization>Sales</organization>
            <location>
                <country>US</country>
                <state>WA</state>
                <city>Bellingham</city>
                <gps>
                    <longitude>-122.499225</longitude>
                    <latitude>48.759553</latitude>
                </gps>
            </location>
            <age>45</age>
            <employDate>2009-06-01</employDate>
            <skills>
                <skill>PowerPoint</skill>
                <skill>PhotoShop</skill>
            </skills>
        </employee>
        <employee>
            <name>Mike</name>
            <sex>Male</sex>
            <organization>Sales</organization>
            <location>
                <country>US</country>
                <state>OR</state>
                <city>Eugene</city>
                <gps>
                    <longitude>-123.086754</longitude>
                    <latitude>44.052069</latitude>
                </gps>
            </location>
            <age>55</age>
            <employDate>1999-06-01</employDate>
            <skills>
                <skill>PowerPoint</skill>
                <skill>Negotiation</skill>
            </skills>
        </employee>
    </sample>

let $employees := $sample/employee
let $facetDefinition :=
    <facet:facet-definition name="Org">
        <facet:group-by>
            <facet:sub-path>organization</facet:sub-path>
        </facet:group-by>
    </facet:facet-definition>
return
    facet:count($employees, $facetDefinition)