Re: [xsl] Seek XPath 2.0 expression for this: Are there any book titles with more than one binding?

Subject: Re: [xsl] Seek XPath 2.0 expression for this: Are there any book titles with more than one binding?
From: "Alan Painter alan.painter@xxxxxxxxx" <xsl-list-service@xxxxxxxxxxxxxxxxxxxxxx>
Date: Sat, 4 May 2019 06:39:48 -0000
Taking Wendell's understanding of the required solution, can do with nested
for-each-group although rather rebarbative:

    <xsl:template match="/">
        <BooksWithMultipleBindings>
            <xsl:for-each-group select="/Bookstore/BookTitle/Book" group-by=
"Author" >
                <xsl:for-each-group select="current-group()" group-by=
"Title">
                    <xsl:for-each-group select="current-group()" group-by=
"Binding">
                        <xsl:sequence select="current-group()[1]" />
                    </xsl:for-each-group>

                </xsl:for-each-group>
            </xsl:for-each-group>
        </BooksWithMultipleBindings>
    </xsl:template>


Other option is with Wendell's signature function and a single
for-each-group:


    <xsl:template match="/">
        <BooksWithMultipleBindings>
            <xsl:for-each-group select="/Bookstore/BookTitle/Book" group-by=
"l:signature(.)" >
                <xsl:sequence select="current-group()[1]" />
            </xsl:for-each-group>
        </BooksWithMultipleBindings>
    </xsl:template>


We'll need to improve the signature function to be sure that the key is
distinct, as the following distinct book-author pairs would produce the
same key with the function as proposed.


        <Book>
            <Author>Cher</Author>
            <Title>Ami_Chanteur</Title>
            <Binding>softcover</Binding>
            <Count>1</Count>
            <Description>do do do ..</Description>
        </Book>
        <Book>
            <Author>Cher_Ami</Author>
            <Title>Chanteur</Title>
            <Binding>softcover</Binding>
            <Count>1</Count>
            <Description>do do do ..</Description>
        </Book>
    </BookTitle>


As an example, I'm thinking that the following function should be distinct
for all possible values:


    <xsl:function name="l:signature" as="xs:string">
        <xsl:param name="book" as="element(Book)"/>
        <xsl:value-of select="concat('Author:',  $book/Author,
string-length($book/Author),
                                     'Title:',   $book/Title,
string-length($book/Title),
                                     'Binding:', $book/Binding)"/>
    </xsl:function>


best regards

On Sat, May 4, 2019 at 1:52 AM Wendell Piez wapiez@xxxxxxxxxxxxxxx <
xsl-list-service@xxxxxxxxxxxxxxxxxxxxxx> wrote:

> As long as we are offering alternatives, how about XSLT?
>
>   <xsl:key name="bound-books" match="Book"
>     use="l:signature(.)"/>
>
>   <xsl:template match="/">
>     <BookList>
>       <xsl:apply-templates select=".//Book"/>
>     </BookList>
>   </xsl:template>
>
>   <xsl:template match="Book"/>
>
>   <xsl:template match="Book[. is key('bound-books',l:signature(.))[1]
> and exists(key('bound-books',l:signature(.))[2])]">
>     <xsl:copy-of select="."/>
>   </xsl:template>
>
>   <xsl:function name="l:signature" as="xs:string">
>     <xsl:param name="book" as="element(Book)"/>
>     <xsl:value-of select="string-join($book/(Author,Title,Binding),'_')"/>
>   </xsl:function>
>
> This might translate the requirements even more directly -- drop a
> book unless it is the first with its title, author and binding and if
> a second of the same title, author and binding can be found.
>
> I *think* that is what was asked for, or the practical equivalent?
>
> Cheers, Wendell
>
>
> On Thu, May 2, 2019 at 12:21 PM Dimitre Novatchev dnovatchev@xxxxxxxxx
> <xsl-list-service@xxxxxxxxxxxxxxxxxxxxxx> wrote:
> >
> > Assuming that there is just one BookBinding for all books with the same
> title by the same author and with the same binding, and also assuming that
> all books with the same title by the same author are in ** contiguous**
> bindings (which is the case with the provided document), then this XPath
> 2.0 expression selects the wanted Book elements. At least for me it seems
> less complex and more understandable than the originally provided expression
> >
> >      "for $b in
> >        /*/*/Book[Author = ../following-sibling::*[1]/Book/Author
> >                  and Title = ../following-sibling::*[1]/Book/Title
> >                  and not(Binding =
> ../following-sibling::*[1]/Book/Binding)
> >                     ][1],
> >        $binding in distinct-values(/*/*/Book[Author = $b/Author and
> Title = $b/Title]/Binding)
> >          return
> >            /*/*/Book[Author = $b/Author and Title = $b/Title and Binding
> = $binding][1]
> >
> >
> > On Thu, May 2, 2019 at 5:55 AM Costello, Roger L. costello@xxxxxxxxx <
> xsl-list-service@xxxxxxxxxxxxxxxxxxxxxx> wrote:
> >>
> >> Hello XPath experts!
> >>
> >> At the bottom of this message is my XML document. I need an XPath 2.0
> expression that returns the result of this query:
> >>
> >>         Are there any book titles with more than
> >>         one binding? If yes, then show the first book
> >>         for each binding.
> >>
> >> For the below XML document, the query should return these two books:
> >>
> >> <Book>
> >>     <Author>Sally Smith</Author>
> >>     <Title>XYZ</Title>
> >>     <Binding>hardcover</Binding>
> >>     <Count>1</Count>
> >>     <Description>lo lo lo ..</Description>
> >> </Book>
> >> <Book>
> >>     <Author>Sally Smith</Author>
> >>     <Title>XYZ</Title>
> >>     <Binding>softcover</Binding>
> >>     <Count>1</Count>
> >>     <Description>do do do ..</Description>
> >> </Book>
> >>
> >> Notice that the two books have the same author and title but different
> binding (hardcover versus softcover).
> >>
> >> This XPath 2.0 expression seems to work:
> >>
> >> for $i in /Bookstore/BookTitle/Book[1],
> >>     $j in /Bookstore/BookTitle/Book[1] return
> >>         if (($i ne $j)
> >>             and ($i/Author eq $j/Author)
> >>             and ($i/Title eq $j/Title)
> >>             and ($i/Binding ne $j/Binding)
> >>             and ($i = $j/preceding::Book))
> >>         then ($i, $j)
> >>         else ()
> >>
> >> That expression seems awfully complicated. Is there a simpler
> expression? If there isn't a simpler expression, then do you see anything
> missing in the expression (i.e., something that the expression doesn't take
> into consideration)?  /Roger
> >>
> >> <Bookstore>
> >>     <BookTitle>
> >>         <Book>
> >>             <Author>John Doe</Author>
> >>             <Title>ABC</Title>
> >>             <Binding>hardcover</Binding>
> >>             <Count>1</Count>
> >>             <Description>da da da ..</Description>
> >>         </Book>
> >>         <Book>
> >>             <Author>John Doe</Author>
> >>             <Title>ABC</Title>
> >>             <Binding>hardcover</Binding>
> >>             <Count>2</Count>
> >>             <Description>za za za ..</Description>
> >>         </Book>
> >>     </BookTitle>
> >>     <BookTitle>
> >>         <Book>
> >>             <Author>John Doe</Author>
> >>             <Title>Foo</Title>
> >>             <Binding>softcover</Binding>
> >>             <Count>1</Count>
> >>             <Description>na na na ..</Description>
> >>         </Book>
> >>     </BookTitle>
> >>     <BookTitle>
> >>         <Book>
> >>             <Author>Sally Smith</Author>
> >>             <Title>XYZ</Title>
> >>             <Binding>hardcover</Binding>
> >>             <Count>1</Count>
> >>             <Description>lo lo lo ..</Description>
> >>         </Book>
> >>         <Book>
> >>             <Author>Sally Smith</Author>
> >>             <Title>XYZ</Title>
> >>             <Binding>hardcover</Binding>
> >>             <Count>2</Count>
> >>             <Description>ho ho ho ..</Description>
> >>         </Book>
> >>     </BookTitle>
> >>     <BookTitle>
> >>         <Book>
> >>             <Author>Sally Smith</Author>
> >>             <Title>XYZ</Title>
> >>             <Binding>softcover</Binding>
> >>             <Count>1</Count>
> >>             <Description>do do do ..</Description>
> >>         </Book>
> >>     </BookTitle>
> >> </Bookstore>
> >>
> >
> >
> > --
> > Cheers,
> > Dimitre Novatchev
> > ---------------------------------------
> > Truly great madness cannot be achieved without significant intelligence.
> > ---------------------------------------
> > To invent, you need a good imagination and a pile of junk
> > -------------------------------------
> > Never fight an inanimate object
> > -------------------------------------
> > To avoid situations in which you might make mistakes may be the
> > biggest mistake of all
> > ------------------------------------
> > Quality means doing it right when no one is looking.
> > -------------------------------------
> > You've achieved success in your field when you don't know whether what
> you're doing is work or play
> > -------------------------------------
> > To achieve the impossible dream, try going to sleep.
> > -------------------------------------
> > Facts do not cease to exist because they are ignored.
> > -------------------------------------
> > Typing monkeys will write all Shakespeare's works in 200yrs.Will they
> write all patents, too? :)
> > -------------------------------------
> > Sanity is madness put to good use.
> > -------------------------------------
> > I finally figured out the only reason to be alive is to enjoy it.
> >
> > XSL-List info and archive
> > EasyUnsubscribe (by email)
>
>
>
> --
> ...Wendell Piez... ...wendell -at- nist -dot- gov...
> ...wendellpiez.com... ...pellucidliterature.org... ...pausepress.org...
> ...github.com/wendellpiez... ...gitlab.coko.foundation/wendell...

Current Thread