xmlxsltmuenchian-groupingmarc

XSL Muenchian grouping works, but how can I count content of all child nodes of the key?


Scenario is this: a library has five books. Author A has written one title, and the library owns two copies that has been ckecked out 30+14=44 times Author B has written two book, and the library owns two copies of Title B that has been checked out 18+9=27 times and one copy of title C that has been checked out 41 times.

My XML looks like this:

<?xml version="1.0" encoding="UTF-8"?>
<?xml-stylesheet type="text/xsl" href="popauthors.xsl"?>
<report>
  <catalog>
    <marc>
      <marcEntry tag="100" label="Personal Author" ind="1 ">Author A</marcEntry>
      <marcEntry tag="245" label="Title" ind="10">Title A</marcEntry>
    </marc>
  <call>
    <item>
      <totalCharges>30</totalCharges>
        <itemID>1234</itemID>
    </item>
    <item>
      <totalCharges>14</totalCharges>
      <itemID>2345</itemID>
    </item>
  </call>
</catalog>
<catalog>
  <marc>
    <marcEntry tag="100" label="Personal Author" ind="1 ">Author B</marcEntry>
    <marcEntry tag="245" label="Title" ind="10">Title B</marcEntry>
  </marc>
  <call>
    <item>
      <totalCharges>18</totalCharges>
      <itemID>3456</itemID>
    </item>
    <item>
      <totalCharges>9</totalCharges>
      <itemID>4567</itemID>
    </item>
  </call>
</catalog>
<catalog>
  <marc>
    <marcEntry tag="100" label="Personal Author" ind="1 ">Author B</marcEntry>
    <marcEntry tag="245" label="Title" ind="10">Title C</marcEntry>
  </marc>
  <call>
    <item>
      <totalCharges>41</totalCharges>
      <itemID>5678</itemID>
    </item>
  </call>
</catalog>
</report>

I tried Muenchian grouping - it gave correct figures for Author A, but for Author B it counted only items and charges for the first title, two items with 27 charges instead of the correct figure 3 items with 68 charges. What should I add to count all charges for an author with multiple titles?

<?xml version="1.0"?>

<xsl:stylesheet version="1.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform">

<xsl:output method="xml" version="1.0" encoding="UTF-8" indent="yes"/>

<xsl:key name="popauthor" match="marc" use="marcEntry[@tag='100']"/>

<xsl:template match="/">
    <popauthors>
        <xsl:for-each select="//marc[generate-id(.)=generate-id(key('popauthor', marcEntry[@tag='100'])[1])]">
            <xsl:sort select="marcEntry"/> 

                <popauthorline>
                    <authorName><xsl:value-of select="marcEntry[@tag='100']"/></authorName>
                    <numberOfTitles><xsl:value-of select="count(key('popauthor', marcEntry[@tag='100']))"/></numberOfTitles>
                    <numberOfItems><xsl:value-of select="count(../call/item/itemID)"/></numberOfItems>
                    <TotalCharges><xsl:value-of select="sum(../call/item/totalCharges)"/></TotalCharges>
                </popauthorline>

        </xsl:for-each>
    </popauthors>
</xsl:template>

</xsl:stylesheet>

Solution

  • It seems to me you want to group the catalog entries, not their marc children. Then everything becomes simpler:

    XSLT 1.0

    <xsl:stylesheet version="1.0" 
    xmlns:xsl="http://www.w3.org/1999/XSL/Transform">
    <xsl:output method="xml" version="1.0" encoding="UTF-8" indent="yes"/>
    
    <xsl:key name="cat-by-auth" match="catalog" use="marc/marcEntry[@tag='100']"/>
    
    <xsl:template match="/report">
        <popauthors>
            <xsl:for-each select="catalog[generate-id(.)=generate-id(key('cat-by-auth', marc/marcEntry[@tag='100'])[1])]">
                <xsl:sort select="marc/marcEntry[@tag='100']"/> 
                <xsl:variable name="titles" select="key('cat-by-auth', marc/marcEntry[@tag='100'])" />
                    <popauthorline>
                        <authorName><xsl:value-of select="marc/marcEntry[@tag='100']"/></authorName>
                        <numberOfTitles><xsl:value-of select="count($titles)"/></numberOfTitles>
                        <numberOfItems><xsl:value-of select="count($titles/call/item)"/></numberOfItems>
                        <TotalCharges><xsl:value-of select="sum($titles/call/item/totalCharges)"/></TotalCharges>
                    </popauthorline>
            </xsl:for-each>
        </popauthors>
    </xsl:template>
    
    </xsl:stylesheet>