jgm / citeproc

CSL citation processing library in Haskell
BSD 2-Clause "Simplified" License
152 stars 14 forks source link

Incorrect sorting of bibliography #126

Closed jpcirrus closed 1 year ago

jpcirrus commented 1 year ago

The bibliography items are not sorted correctly when using an author-date csl stylesheet and with two or more items having the same year but not the same date specificity:

pandoc --citeproc -t plain  << EOT
---
references:
  - id: americancollegeofsportsmedicine1975
    author:
      - family: American College of Sports Medicine
        given: ''
    citation-key: americancollegeofsportsmedicine1975
    issued:
      - year: 1975
    title: Guidelines for graded exercise testing and exercise prescription
    type: book
  - id: americancollegeofsportsmedicine2013
    author:
      - family: American College of Sports Medicine
        given: ''
    citation-key: americancollegeofsportsmedicine2013
    issued:
      - year: 2013
    title: ACSM's resource manual for guidelines for exercise testing and prescription
    type: book
  - id: americancollegeofsportsmedicine2018
    author:
      - family: American College of Sports Medicine
        given: ''
    citation-key: americancollegeofsportsmedicine2018
    issued:
      - year: 2018
    title: ACSM's exercise testing and prescription
    type: book
  - id: americancollegeofsportsmedicine2021
    accessed:
      - year: 2021
        month: 12
        day: 15
    author:
      - family: American College of Sports Medicine
        given: ''
    citation-key: americancollegeofsportsmedicine2021
    issued:
      - year: 2021
        month: 11
        day: 10
    title: The American College of Sports Medicine
    type: webpage
    URL: https://bit.ly/3DSQHc8
  - id: americancollegeofsportsmedicine2021a
    author:
      - family: American College of Sports Medicine
        given: ''
    citation-key: americancollegeofsportsmedicine2021a
    issued:
      - year: 2021
    title: ACSM's guidelines for exercise testing and prescription
    type: book
nocite: |
  @*
...
EOT

Which ouputs:

American College of Sports Medicine. (2021a, November 10). The American College of Sports Medicine. https://bit.ly/3DSQHc8
American College of Sports Medicine. (1975). Guidelines for graded exercise testing and exercise prescription.
American College of Sports Medicine. (2013). ACSM’s resource manual for guidelines for exercise testing and prescription.
American College of Sports Medicine. (2018). ACSM’s exercise testing and prescription.
American College of Sports Medicine. (2021b). ACSM’s guidelines for exercise testing and prescription.

instead of the expected, and which is output directly in a Zotero bibliography export:

American College of Sports Medicine. (1975). Guidelines for graded exercise testing and exercise prescription.
American College of Sports Medicine. (2013). ACSM’s resource manual for guidelines for exercise testing and prescription.
American College of Sports Medicine. (2018). ACSM’s exercise testing and prescription.
American College of Sports Medicine. (2021a). ACSM’s guidelines for exercise testing and prescription.
American College of Sports Medicine. (2021b, November 10). The American College of Sports Medicine. https://bit.ly/3DSQHc8

As is seen: the two 2021 items are sorted incorrectly and with the wrong year suffixes. I think this could be the same issue that was reported in jgm/pandoc-citeproc#416 and fixed in pandoc 2.11.

jgm commented 1 year ago

The test for pandoc-citeproc 416 is still there and it passes, so it may be a somewhat different issue.

jgm commented 1 year ago

Hm, I just tried this and got a different result.

American College of Sports Medicine. 1975. Guidelines for Graded
Exercise Testing and Exercise Prescription.

———. 2013. ACSM’s Resource Manual for Guidelines for Exercise Testing
and Prescription.

———. 2018. ACSM’s Exercise Testing and Prescription.

———. 2021a. ACSM’s Guidelines for Exercise Testing and Prescription.

———. 2021b. “The American College of Sports Medicine.” November 10,
2021. https://bit.ly/3DSQHc8.
jgm commented 1 year ago

This is with

pandoc 2.19.2
Compiled with pandoc-types 1.22.2.1, texmath 0.12.5.2, skylighting 0.13,
citeproc 0.8.0.1, ipynb 0.2, hslua 2.2.1

(Edit: also tried with the current dev version of pandoc, which uses the latest citeproc.)

jpcirrus commented 1 year ago

I was on the same pandoc release version, but your different result led me to discover that many years ago I had created a default.csl symlink to the apa.csl in the pandoc data directory. Renaming that then gives your result indicating the error is in the apa.csl stylesheet which I will investigate. Thank you for your assistance and sorry for wasting your time.

jgm commented 1 year ago

Perhaps there is still a problem with pandoc, but one that only arises with the apa stylesheet? I'll reopen this until you confirm.

jgm commented 1 year ago

I get the correct sort order with both apa 5th and apa 6th edition stylesheets. Maybe you have a very old version of the stylesheet? In any case, I think I'll close, but comment here if there are further developments.

jpcirrus commented 1 year ago

Yes, this is a pandoc (citeproc) issue, but only seems to occur with the APA 7th edition stylesheet (apa.csl). Sorry, I'm a bit under the weather with flu at the moment and forgot that I had initially stated that a direct bibliography export from Zotero provides the correct sort order with that stylesheet, so it's not the stylesheet. And, testing with the 6th edition stylesheet (pandoc --citeproc --csl=apa-6th-edition -t plain) gives the expected sort order.

jgm commented 1 year ago

Here's a pure citeproc test case:

>>===== MODE =====>>
bibliography
<<===== MODE =====<<

>>===== RESULT =====>>
<div class="csl-bib-body">
  <div class="csl-entry">American College of Sports Medicine. (1975). <i>Guidelines for graded exercise testing and exercise prescription</i>.</div>
  <div class="csl-entry">American College of Sports Medicine. (2013). <i>ACSM’s resource manual for guidelines for exercise testing and prescription</i>.</div>
  <div class="csl-entry">American College of Sports Medicine. (2018). <i>ACSM’s exercise testing and prescription</i>.</div>
  <div class="csl-entry">American College of Sports Medicine. (2021a). <i>ACSM’s guidelines for exercise testing and prescription</i>.</div>
  <div class="csl-entry">American College of Sports Medicine. (2021b, November 10). <i>The American College of Sports Medicine</i>. https://bit.ly/3DSQHc8</div>
</div>
<<===== RESULT =====<<

>>===== CSL =====>>
<?xml version="1.0" encoding="utf-8"?>
<style xmlns="http://purl.org/net/xbiblio/csl" class="in-text" version="1.0" demote-non-dropping-particle="never" page-range-format="expanded">
  <info>
    <title>American Psychological Association 7th edition</title>
    <title-short>APA</title-short>
    <id>http://www.zotero.org/styles/apa</id>
    <link href="http://www.zotero.org/styles/apa" rel="self"/>
    <link href="http://www.zotero.org/styles/apa-6th-edition" rel="template"/>
    <link href="https://apastyle.apa.org/style-grammar-guidelines/references/examples" rel="documentation"/>
    <author>
      <name>Brenton M. Wiernik</name>
      <email>zotero@wiernik.org</email>
    </author>
    <category citation-format="author-date"/>
    <category field="psychology"/>
    <category field="generic-base"/>
    <updated>2022-01-31T14:30:00+00:00</updated>
    <rights license="http://creativecommons.org/licenses/by-sa/3.0/">This work is licensed under a Creative Commons Attribution-ShareAlike 3.0 License</rights>
  </info>
  <locale xml:lang="en">
    <terms>
      <term name="editortranslator" form="short">
        <single>ed. &amp; trans.</single>
        <multiple>eds. &amp; trans.</multiple>
      </term>
      <term name="translator" form="short">trans.</term>
      <term name="interviewer" form="short">
        <single>interviewer</single>
        <multiple>interviewers</multiple>
      </term>
      <term name="collection-editor" form="short">
        <single>ed.</single>
        <multiple>eds.</multiple>
      </term>
      <term name="circa" form="short">ca.</term>
      <term name="bc"> B.C.E.</term>
      <term name="ad"> C.E.</term>
      <term name="letter">personal communication</term>
      <term name="letter" form="short">letter</term>
      <term name="issue" form="long">
        <single>issue</single>
        <multiple>issues</multiple>
      </term>
    </terms>
  </locale>
  <macro name="author-bib">
    <names variable="composer" delimiter=", ">
      <name name-as-sort-order="all" and="symbol" sort-separator=", " initialize-with=". " delimiter=", " delimiter-precedes-last="always"/>
      <substitute>
        <names variable="author"/>
        <names variable="illustrator"/>
        <names variable="director">
          <name name-as-sort-order="all" and="symbol" sort-separator=", " initialize-with=". " delimiter=", " delimiter-precedes-last="always"/>
          <label form="long" prefix=" (" suffix=")" text-case="title"/>
        </names>
        <choose>
          <if variable="container-title">
            <choose>
              <if type="book entry entry-dictionary entry-encyclopedia" match="any">
                <choose>
                  <if variable="title">
                    <group delimiter=" ">
                      <text macro="title"/>
                      <text macro="parenthetical"/>
                    </group>
                  </if>
                  <else>
                    <text macro="title-and-descriptions"/>
                  </else>
                </choose>
              </if>
            </choose>
          </if>
        </choose>
        <!-- Test for editortranslator and put that first as that becomes available -->
        <names variable="editor" delimiter=", ">
          <name name-as-sort-order="all" and="symbol" sort-separator=", " initialize-with=". " delimiter=", " delimiter-precedes-last="always"/>
          <label form="short" prefix=" (" suffix=")" text-case="title"/>
        </names>
        <names variable="editorial-director">
          <name name-as-sort-order="all" and="symbol" sort-separator=", " initialize-with=". " delimiter=", " delimiter-precedes-last="always"/>
          <label form="short" prefix=" (" suffix=")" text-case="title"/>
        </names>
        <names variable="collection-editor">
          <name name-as-sort-order="all" and="symbol" sort-separator=", " initialize-with=". " delimiter=", " delimiter-precedes-last="always"/>
          <label form="short" prefix=" (" suffix=")" text-case="title"/>
        </names>
        <choose>
          <if variable="title">
            <group delimiter=" ">
              <text macro="title"/>
              <text macro="parenthetical"/>
            </group>
          </if>
          <else>
            <text macro="title-and-descriptions"/>
          </else>
        </choose>
      </substitute>
    </names>
  </macro>
  <macro name="author-intext">
    <choose>
      <if type="bill legal_case legislation treaty" match="any">
        <text macro="title-intext"/>
      </if>
      <else-if type="interview personal_communication" match="any">
        <choose>
          <!-- These variables indicate that the letter is retrievable by the reader.
                If not, then use the APA in-text-only personal communication format -->
          <if variable="archive container-title DOI publisher URL" match="none">
            <group delimiter=", ">
              <names variable="author">
                <name and="symbol" delimiter=", " initialize-with=". "/>
                <substitute>
                  <text macro="title-intext"/>
                </substitute>
              </names>
              <!-- Replace with term="personal-communication" if that becomes available -->
              <text term="letter"/>
            </group>
          </if>
          <else>
            <names variable="author" delimiter=", ">
              <name form="short" and="symbol" delimiter=", " initialize-with=". "/>
              <substitute>
                <text macro="title-intext"/>
              </substitute>
            </names>
          </else>
        </choose>
      </else-if>
      <else>
        <names variable="composer" delimiter=", ">
          <name form="short" and="symbol" delimiter=", " initialize-with=". "/>
          <substitute>
            <names variable="author"/>
            <names variable="illustrator"/>
            <names variable="director"/>
            <choose>
              <if variable="container-title">
                <choose>
                  <if type="book entry entry-dictionary entry-encyclopedia" match="any">
                    <text macro="title-intext"/>
                  </if>
                </choose>
              </if>
            </choose>
            <names variable="editor"/>
            <names variable="editorial-director"/>
            <text macro="title-intext"/>
          </substitute>
        </names>
      </else>
    </choose>
  </macro>
  <macro name="date-bib">
    <group delimiter=" " prefix="(" suffix=")">
      <choose>
        <if is-uncertain-date="issued">
          <text term="circa" form="short"/>
        </if>
      </choose>
      <group>
        <choose>
          <if variable="issued">
            <date variable="issued">
              <date-part name="year"/>
            </date>
            <text variable="year-suffix"/>
            <choose>
              <if type="article-magazine article-newspaper broadcast interview motion_picture pamphlet personal_communication post post-weblog song speech webpage" match="any">
                <!-- Many video and audio examples in manual give full dates. Err on the side of too much information. -->
                <date variable="issued">
                  <date-part prefix=", " name="month"/>
                  <date-part prefix=" " name="day"/>
                </date>
              </if>
              <else-if type="paper-conference">
                <!-- Capture 'speech' stored as 'paper-conference' -->
                <choose>
                  <if variable="collection-editor editor editorial-director issue page volume" match="none">
                    <date variable="issued">
                      <date-part prefix=", " name="month"/>
                      <date-part prefix=" " name="day"/>
                    </date>
                  </if>
                </choose>
              </else-if>
              <!-- Only year: article article-journal book chapter entry entry-dictionary entry-encyclopedia dataset figure graphic
                   manuscript map musical_score paper-conference[published] patent report review review-book thesis -->
            </choose>
          </if>
          <else-if variable="status">
            <group>
              <text variable="status" text-case="lowercase"/>
              <text variable="year-suffix" prefix="-"/>
            </group>
          </else-if>
          <else>
            <text term="no date" form="short"/>
            <text variable="year-suffix" prefix="-"/>
          </else>
        </choose>
      </group>
    </group>
  </macro>
  <macro name="date-sort-group">
    <!-- APA sorts 1. no-date items, 2. items with dates, 3. in-press (status) items -->
    <choose>
      <if variable="issued">
        <text value="1"/>
      </if>
      <else-if variable="status">
        <text value="2"/>
      </else-if>
      <else>
        <text value="0"/>
      </else>
    </choose>
  </macro>
  <macro name="date-sort-date">
    <date variable="issued" form="numeric"/>
  </macro>
  <macro name="date-intext">
    <choose>
      <if variable="issued">
        <group delimiter="/">
          <group delimiter=" ">
            <choose>
              <if is-uncertain-date="original-date">
                <text term="circa" form="short"/>
              </if>
            </choose>
            <date variable="original-date">
              <date-part name="year"/>
            </date>
          </group>
          <group delimiter=" ">
            <choose>
              <if is-uncertain-date="issued">
                <text term="circa" form="short"/>
              </if>
            </choose>
            <group>
              <choose>
                <if type="interview personal_communication" match="any">
                  <choose>
                    <if variable="archive container-title DOI publisher URL" match="none">
                      <!-- These variables indicate that the communication is retrievable by the reader.
                           If not, then use the in-text-only personal communication format -->
                      <date variable="issued" form="text"/>
                    </if>
                    <else>
                      <date variable="issued">
                        <date-part name="year"/>
                      </date>
                    </else>
                  </choose>
                </if>
                <else>
                  <date variable="issued">
                    <date-part name="year"/>
                  </date>
                </else>
              </choose>
              <text variable="year-suffix"/>
            </group>
          </group>
        </group>
      </if>
      <else-if variable="status">
        <text variable="status" text-case="lowercase"/>
        <text variable="year-suffix" prefix="-"/>
      </else-if>
      <else>
        <text term="no date" form="short"/>
        <text variable="year-suffix" prefix="-"/>
      </else>
    </choose>
  </macro>
  <!-- APA has two description elements following the title:
       title (parenthetical) [bracketed]  -->
  <macro name="title-and-descriptions">
    <choose>
      <if variable="title">
        <group delimiter=" ">
          <text macro="title"/>
          <text macro="parenthetical"/>
          <text macro="bracketed"/>
        </group>
      </if>
      <else>
        <group delimiter=" ">
          <text macro="bracketed"/>
          <text macro="parenthetical"/>
        </group>
      </else>
    </choose>
  </macro>
  <macro name="title">
    <choose>
      <if type="post webpage" match="any">
        <!-- Webpages are always italicized -->
        <text variable="title" font-style="italic"/>
      </if>
      <else-if variable="container-title" match="any">
        <!-- Other types are italicized based on presence of container-title.
             Assume that review and review-book are published in periodicals/blogs,
             not just on a web page (ex. 69) -->
        <text variable="title"/>
      </else-if>
      <else>
        <choose>
          <if type="article-journal article-magazine article-newspaper post-weblog review review-book" match="any">
            <text variable="title" font-style="italic"/>
          </if>
          <else-if type="paper-conference">
            <choose>
              <if variable="collection-editor editor editorial-director" match="any">
                <group delimiter=": " font-style="italic">
                  <text variable="title"/>
                  <!-- Replace with volume-title as that becomes available -->
                  <choose>
                    <if is-numeric="volume" match="none">
                      <group delimiter=" ">
                        <label variable="volume" form="short" text-case="capitalize-first"/>
                        <text variable="volume"/>
                      </group>
                    </if>
                  </choose>
                </group>
              </if>
              <else>
                <text variable="title" font-style="italic"/>
              </else>
            </choose>
          </else-if>
          <else>
            <group delimiter=": " font-style="italic">
              <text variable="title"/>
              <!-- Replace with volume-title as that becomes available -->
              <choose>
                <if is-numeric="volume" match="none">
                  <group delimiter=" ">
                    <label variable="volume" form="short" text-case="capitalize-first"/>
                    <text variable="volume"/>
                  </group>
                </if>
              </choose>
            </group>
          </else>
        </choose>
      </else>
    </choose>
  </macro>
  <macro name="title-intext">
    <choose>
      <if variable="title" match="none">
        <text macro="bracketed-intext" prefix="[" suffix="]"/>
      </if>
      <else-if type="bill">
        <!-- If a bill has no number or container-title, assume it is a hearing; italic -->
        <choose>
          <if variable="number container-title" match="none">
            <text variable="title" form="short" font-style="italic" text-case="title"/>
          </if>
          <else-if variable="title">
            <text variable="title" form="short" text-case="title"/>
          </else-if>
          <else>
            <group delimiter=" ">
              <text variable="genre"/>
              <group delimiter=" ">
                <choose>
                  <if variable="chapter-number container-title" match="none">
                    <!-- Replace with label variable="number" as that becomes available -->
                    <text term="issue" form="short"/>
                  </if>
                </choose>
                <text variable="number"/>
              </group>
            </group>
          </else>
        </choose>
      </else-if>
      <else-if type="legal_case" match="any">
        <!-- Cases are italicized -->
        <text variable="title" font-style="italic"/>
      </else-if>
      <else-if type="legislation treaty" match="any">
        <!-- Legislation and treaties not italicized or quoted -->
        <text variable="title" form="short" text-case="title"/>
      </else-if>
      <else-if type="post webpage" match="any">
        <!-- Webpages are always italicized -->
        <text variable="title" form="short" font-style="italic" text-case="title"/>
      </else-if>
      <else-if variable="container-title" match="any">
        <!-- Other types are italicized or quoted based on presence of container-title. As in title macro. -->
        <text variable="title" form="short" quotes="true" text-case="title"/>
      </else-if>
      <else>
        <text variable="title" form="short" font-style="italic" text-case="title"/>
      </else>
    </choose>
  </macro>
  <macro name="parenthetical">
    <!-- (Secondary contributors; Database location; Genre no. 123; Report Series 123, Version, Edition, Volume, Page) -->
    <group prefix="(" suffix=")">
      <choose>
        <if type="patent">
          <!-- authority: U.S. ; genre: patent ; number: 123,445 -->
          <group delimiter=" ">
            <text variable="authority" form="short"/>
            <choose>
              <if variable="genre">
                <text variable="genre" text-case="capitalize-first"/>
              </if>
              <else>
                <!-- This should be localized -->
                <text value="patent" text-case="capitalize-first"/>
              </else>
            </choose>
            <group delimiter=" ">
              <!-- Replace with label variable="number" if that becomes available -->
              <text term="issue" form="short" text-case="capitalize-first"/>
              <text variable="number"/>
            </group>
          </group>
        </if>
        <else-if type="post webpage" match="any">
          <!-- For post webpage, container-title is treated as publisher -->
          <group delimiter="; ">
            <text macro="secondary-contributors"/>
            <text macro="database-location"/>
            <text macro="number"/>
            <text macro="locators-booklike"/>
          </group>
        </else-if>
        <else-if variable="container-title">
          <group delimiter="; ">
            <text macro="secondary-contributors"/>
            <choose>
              <if type="broadcast graphic map motion_picture song" match="any">
                <!-- For audiovisual media, number information comes after title, not container-title -->
                <text macro="number"/>
              </if>
            </choose>
          </group>
        </else-if>
        <else>
          <group delimiter="; ">
            <text macro="secondary-contributors"/>
            <text macro="database-location"/>
            <text macro="number"/>
            <text macro="locators-booklike"/>
          </group>
        </else>
      </choose>
    </group>
  </macro>
  <macro name="parenthetical-container">
    <choose>
      <if variable="container-title" match="any">
        <group prefix="(" suffix=")">
          <group delimiter="; ">
            <text macro="database-location"/>
            <choose>
              <if type="broadcast graphic map motion_picture song" match="none">
                <!-- For audiovisual media, number information comes after title, not container-title -->
                <text macro="number"/>
              </if>
            </choose>
            <text macro="locators-booklike"/>
          </group>
        </group>
      </if>
    </choose>
  </macro>
  <macro name="bracketed">
    <!-- [Descriptive information] -->
    <!-- If there is a number, genre is already printed in macro="number" -->
    <group prefix="[" suffix="]">
      <choose>
        <if variable="reviewed-author reviewed-title" type="review review-book" match="any">
          <!-- Reviewed item -->
          <group delimiter="; ">
            <group delimiter=", ">
              <group delimiter=" ">
                <!-- Assume that genre is entered as 'Review of the book' or similar -->
                <choose>
                  <if variable="number" match="none">
                    <choose>
                      <if variable="genre">
                        <text variable="genre" text-case="capitalize-first"/>
                      </if>
                      <else-if variable="medium">
                        <text variable="medium" text-case="capitalize-first"/>
                      </else-if>
                      <else>
                        <!-- Replace with term="review" as that becomes available -->
                        <text value="Review of"/>
                      </else>
                    </choose>
                  </if>
                  <else>
                    <choose>
                      <if variable="medium">
                        <text variable="medium" text-case="capitalize-first"/>
                      </if>
                      <else>
                        <!-- Replace with term="review" as that becomes available -->
                        <text value="Review of"/>
                      </else>
                    </choose>
                  </else>
                </choose>
                <text macro="reviewed-title"/>
              </group>
              <names variable="reviewed-author">
                <label form="verb-short" suffix=" "/>
                <name and="symbol" initialize-with=". " delimiter=", "/>
              </names>
            </group>
            <choose>
              <if variable="genre" match="any">
                <choose>
                  <if variable="number" match="none">
                    <text variable="medium" text-case="capitalize-first"/>
                  </if>
                </choose>
              </if>
            </choose>
          </group>
        </if>
        <else-if type="thesis">
          <!-- Thesis type and institution -->
          <group delimiter="; ">
            <choose>
              <if variable="number" match="none">
                <group delimiter=", ">
                  <text variable="genre" text-case="capitalize-first"/>
                  <choose>
                    <if variable="archive DOI URL" match="any">
                      <!-- Include the university in brackets if thesis is published -->
                      <text variable="publisher"/>
                    </if>
                  </choose>
                </group>
              </if>
            </choose>
            <text variable="medium" text-case="capitalize-first"/>
          </group>
        </else-if>
        <else-if variable="interviewer" type="interview" match="any">
          <!-- Interview information -->
          <choose>
            <if variable="title">
              <text macro="format"/>
            </if>
            <else-if variable="genre">
              <group delimiter="; ">
                <group delimiter=" ">
                  <text variable="genre" text-case="capitalize-first"/>
                  <group delimiter=" ">
                    <text term="author" form="verb"/>
                    <names variable="interviewer">
                      <name and="symbol" initialize-with=". " delimiter=", "/>
                    </names>
                  </group>
                </group>
              </group>
            </else-if>
            <else-if variable="interviewer">
              <group delimiter="; ">
                <names variable="interviewer">
                  <label form="verb" suffix=" " text-case="capitalize-first"/>
                  <name and="symbol" initialize-with=". " delimiter=", "/>
                </names>
                <text variable="medium" text-case="capitalize-first"/>
              </group>
            </else-if>
            <else>
              <text macro="format"/>
            </else>
          </choose>
        </else-if>
        <else-if type="personal_communication">
          <!-- Letter information -->
          <choose>
            <if variable="recipient">
              <group delimiter="; ">
                <group delimiter=" ">
                  <choose>
                    <if variable="number" match="none">
                      <choose>
                        <if variable="genre">
                          <text variable="genre" text-case="capitalize-first"/>
                        </if>
                        <else-if variable="medium">
                          <text variable="medium" text-case="capitalize-first"/>
                        </else-if>
                        <else>
                          <text term="letter" form="short" text-case="capitalize-first"/>
                        </else>
                      </choose>
                    </if>
                    <else>
                      <choose>
                        <if variable="medium">
                          <text variable="medium" text-case="capitalize-first"/>
                        </if>
                        <else>
                          <text term="letter" form="short" text-case="capitalize-first"/>
                        </else>
                      </choose>
                    </else>
                  </choose>
                  <names variable="recipient" delimiter=", ">
                    <label form="verb" suffix=" "/>
                    <name and="symbol" delimiter=", "/>
                  </names>
                </group>
                <choose>
                  <if variable="genre" match="any">
                    <choose>
                      <if variable="number" match="none">
                        <text variable="medium" text-case="capitalize-first"/>
                      </if>
                    </choose>
                  </if>
                </choose>
              </group>
            </if>
            <else>
              <text macro="format"/>
            </else>
          </choose>
        </else-if>
        <else-if variable="composer" type="song" match="all">
          <!-- Performer of classical music works -->
          <group delimiter="; ">
            <choose>
              <if variable="number" match="none">
                <group delimiter=" ">
                  <choose>
                    <if variable="genre">
                      <text variable="genre" text-case="capitalize-first"/>
                      <!-- Replace prefix with performer label as that becomes available -->
                      <names variable="author" prefix="recorded by ">
                        <name and="symbol" initialize-with=". " delimiter=", "/>
                      </names>
                    </if>
                    <else-if variable="medium">
                      <text variable="medium" text-case="capitalize-first"/>
                      <!-- Replace prefix with performer label as that becomes available -->
                      <names variable="author" prefix="recorded by ">
                        <name and="symbol" initialize-with=". " delimiter=", "/>
                      </names>
                    </else-if>
                    <else>
                      <!-- Replace prefix with performer label as that becomes available -->
                      <names variable="author" prefix="Recorded by ">
                        <name and="symbol" initialize-with=". " delimiter=", "/>
                      </names>
                    </else>
                  </choose>
                </group>
              </if>
              <else>
                <group delimiter=" ">
                  <choose>
                    <if variable="medium">
                      <text variable="medium" text-case="capitalize-first"/>
                      <!-- Replace prefix with performer label as that becomes available -->
                      <names variable="author" prefix="recorded by ">
                        <name and="symbol" initialize-with=". " delimiter=", "/>
                      </names>
                    </if>
                    <else>
                      <!-- Replace prefix with performer label as that becomes available -->
                      <names variable="author" prefix="Recorded by ">
                        <name and="symbol" initialize-with=". " delimiter=", "/>
                      </names>
                    </else>
                  </choose>
                </group>
              </else>
            </choose>
            <choose>
              <if variable="genre" match="any">
                <choose>
                  <if variable="number" match="none">
                    <text variable="medium" text-case="capitalize-first"/>
                  </if>
                </choose>
              </if>
            </choose>
          </group>
        </else-if>
        <else-if variable="container-title" match="none">
          <!-- Other description -->
          <text macro="format"/>
        </else-if>
        <else>
          <!-- For conference presentations, chapters in reports, software, place bracketed after the container title -->
          <choose>
            <if type="paper-conference speech" match="any">
              <choose>
                <if variable="collection-editor editor editorial-director issue page volume" match="any">
                  <text macro="format"/>
                </if>
              </choose>
            </if>
            <else-if type="book">
              <choose>
                <if variable="version" match="none">
                  <text macro="format"/>
                </if>
              </choose>
            </else-if>
            <else-if type="report" match="none">
              <text macro="format"/>
            </else-if>
          </choose>
        </else>
      </choose>
    </group>
  </macro>
  <macro name="bracketed-intext">
    <group prefix="[" suffix="]">
      <choose>
        <if variable="reviewed-author reviewed-title" type="review review-book" match="any">
          <!-- This should be localized -->
          <text macro="reviewed-title-intext" prefix="Review of "/>
        </if>
        <else-if variable="interviewer" type="interview" match="any">
          <names variable="interviewer">
            <label form="verb" suffix=" " text-case="capitalize-first"/>
            <name and="symbol" initialize-with=". " delimiter=", "/>
            <substitute>
              <text macro="format-intext"/>
            </substitute>
          </names>
        </else-if>
        <else-if type="personal_communication">
          <!-- Letter information -->
          <choose>
            <if variable="recipient">
              <group delimiter=" ">
                <choose>
                  <if variable="number" match="none">
                    <text variable="genre" text-case="capitalize-first"/>
                  </if>
                  <else>
                    <text term="letter" form="short" text-case="capitalize-first"/>
                  </else>
                </choose>
                <names variable="recipient" delimiter=", ">
                  <label form="verb" suffix=" "/>
                  <name and="symbol" delimiter=", "/>
                </names>
              </group>
            </if>
            <else>
              <text macro="format-intext"/>
            </else>
          </choose>
        </else-if>
        <else>
          <text macro="format-intext"/>
        </else>
      </choose>
    </group>
  </macro>
  <macro name="bracketed-container">
    <group prefix="[" suffix="]">
      <choose>
        <if type="paper-conference speech" match="any">
          <!-- Conference presentations should describe the session [container] in bracketed unless published in a proceedings -->
          <choose>
            <if variable="collection-editor editor editorial-director issue page volume" match="none">
              <text macro="format"/>
            </if>
          </choose>
        </if>
        <else-if type="book" variable="version" match="all">
          <!-- For entries in mobile app reference works, place bracketed after the container-title -->
          <text macro="format"/>
        </else-if>
        <else-if type="report">
          <!-- For chapters in reports, place bracketed after the container title -->
          <text macro="format"/>
        </else-if>
      </choose>
    </group>
  </macro>
  <macro name="secondary-contributors">
    <choose>
      <if type="article-journal article-magazine article-newspaper post-weblog review review-book" match="any">
        <text macro="secondary-contributors-periodical"/>
      </if>
      <else-if type="paper-conference">
        <choose>
          <if variable="collection-editor editor editorial-director" match="any">
            <text macro="secondary-contributors-booklike"/>
          </if>
          <else>
            <text macro="secondary-contributors-periodical"/>
          </else>
        </choose>
      </else-if>
      <else>
        <text macro="secondary-contributors-booklike"/>
      </else>
    </choose>
  </macro>
  <macro name="secondary-contributors-periodical">
    <group delimiter="; ">
      <choose>
        <if variable="title">
          <names variable="interviewer" delimiter="; ">
            <name and="symbol" initialize-with=". " delimiter=", "/>
            <label form="short" prefix=", " text-case="title"/>
          </names>
        </if>
      </choose>
      <names variable="translator" delimiter="; ">
        <name and="symbol" initialize-with=". " delimiter=", "/>
        <label form="short" prefix=", " text-case="title"/>
      </names>
    </group>
  </macro>
  <macro name="secondary-contributors-booklike">
    <group delimiter="; ">
      <choose>
        <if variable="title">
          <names variable="interviewer">
            <name and="symbol" initialize-with=". " delimiter=", "/>
            <label form="short" prefix=", " text-case="title"/>
          </names>
        </if>
      </choose>
      <!-- When editortranslator becomes available, add a test: variable="editortranslator" match="none"; then print translator -->
      <choose>
        <if type="post webpage" match="none">
          <!-- Webpages treat container-title like publisher -->
          <choose>
            <if variable="container-title" match="none">
              <group delimiter="; ">
                <names variable="container-author">
                  <label form="verb-short" suffix=" " text-case="title"/>
                  <name and="symbol" initialize-with=". " delimiter=", "/>
                </names>
                <names variable="editor translator" delimiter="; ">
                  <name and="symbol" initialize-with=". " delimiter=", "/>
                  <label form="short" prefix=", " text-case="title"/>
                </names>
              </group>
            </if>
          </choose>
        </if>
        <else>
          <group delimiter="; ">
            <names variable="container-author">
              <label form="verb-short" suffix=" " text-case="title"/>
              <name and="symbol" initialize-with=". " delimiter=", "/>
            </names>
            <names variable="editor translator" delimiter="; ">
              <name and="symbol" initialize-with=". " delimiter=", "/>
              <label form="short" prefix=", " text-case="title"/>
            </names>
          </group>
        </else>
      </choose>
    </group>
  </macro>
  <macro name="database-location">
    <choose>
      <if variable="archive-place" match="none">
        <!-- With `archive-place`: physical archives. Without: online archives. -->
        <!-- Add archive_collection as that becomes available -->
        <text variable="archive_location"/>
      </if>
    </choose>
  </macro>
  <macro name="number">
    <choose>
      <if variable="number">
        <group delimiter=", ">
          <group delimiter=" ">
            <text variable="genre" text-case="title"/>
            <choose>
              <if is-numeric="number">
                <!-- Replace with label variable="number" if that becomes available -->
                <text term="issue" form="short" text-case="capitalize-first"/>
                <text variable="number"/>
              </if>
              <else>
                <text variable="number"/>
              </else>
            </choose>
          </group>
          <choose>
            <if type="thesis">
              <choose>
                <!-- Include the university in brackets if thesis is published -->
                <if variable="archive DOI URL" match="any">
                  <text variable="publisher"/>
                </if>
              </choose>
            </if>
          </choose>
        </group>
      </if>
    </choose>
  </macro>
  <macro name="locators-booklike">
    <choose>
      <if type="article-journal article-magazine article-newspaper broadcast interview patent post post-weblog review review-book speech webpage" match="any"/>
      <else-if type="paper-conference">
        <choose>
          <if variable="collection-editor editor editorial-director" match="any">
            <group delimiter=", ">
              <text macro="version"/>
              <text macro="edition"/>
              <text macro="volume-booklike"/>
            </group>
          </if>
        </choose>
      </else-if>
      <else>
        <group delimiter=", ">
          <text macro="version"/>
          <text macro="edition"/>
          <text macro="volume-booklike"/>
        </group>
      </else>
    </choose>
  </macro>
  <macro name="version">
    <choose>
      <if is-numeric="version">
        <group delimiter=" ">
          <!-- replace with label variable="version" if that becomes available -->
          <text term="version" text-case="capitalize-first"/>
          <text variable="version"/>
        </group>
      </if>
      <else>
        <text variable="version"/>
      </else>
    </choose>
  </macro>
  <macro name="edition">
    <choose>
      <if is-numeric="edition">
        <group delimiter=" ">
          <number variable="edition" form="ordinal"/>
          <label variable="edition" form="short"/>
        </group>
      </if>
      <else>
        <text variable="edition"/>
      </else>
    </choose>
  </macro>
  <macro name="volume-booklike">
    <group delimiter=", ">
      <!-- Report series [ex. 52] -->
      <choose>
        <if type="report">
          <group delimiter=" ">
            <text variable="collection-title" text-case="title"/>
            <text variable="collection-number"/>
          </group>
        </if>
      </choose>
      <choose>
        <if variable="volume" match="any">
          <choose>
            <!-- Non-numeric volumes are already printed as part of the book title -->
            <if is-numeric="volume" match="none"/>
            <else>
              <group delimiter=" ">
                <label variable="volume" form="short" text-case="capitalize-first"/>
                <number variable="volume" form="numeric"/>
              </group>
            </else>
          </choose>
        </if>
        <else>
          <group>
            <!-- Replace with label variable="number-of-volumes" if that becomes available -->
            <text term="volume" form="short" text-case="capitalize-first" suffix=" "/>
            <text term="page-range-delimiter" prefix="1"/>
            <number variable="number-of-volumes" form="numeric"/>
          </group>
        </else>
      </choose>
      <group delimiter=" ">
        <label variable="issue" text-case="capitalize-first"/>
        <text variable="issue"/>
      </group>
      <group delimiter=" ">
        <label variable="page" form="short" suffix=" "/>
        <text variable="page"/>
      </group>
    </group>
  </macro>
  <macro name="reviewed-title">
    <choose>
      <if variable="reviewed-title">
        <!-- Not possible to distinguish TV series episode from other reviewed
              works [Ex. 69] -->
        <text variable="reviewed-title" font-style="italic"/>
      </if>
      <else>
        <!-- Assume title is title of reviewed work -->
        <text variable="title" font-style="italic"/>
      </else>
    </choose>
  </macro>
  <macro name="reviewed-title-intext">
    <choose>
      <if variable="reviewed-title">
        <!-- Not possible to distinguish TV series episode from other reviewed works [Ex. 69] -->
        <text variable="reviewed-title" form="short" font-style="italic" text-case="title"/>
      </if>
      <else>
        <!-- Assume title is title of reviewed work -->
        <text variable="title" form="short" font-style="italic" text-case="title"/>
      </else>
    </choose>
  </macro>
  <macro name="format">
    <choose>
      <if variable="genre medium" match="any">
        <group delimiter="; ">
          <choose>
            <if variable="number" match="none">
              <text variable="genre" text-case="capitalize-first"/>
            </if>
          </choose>
          <text variable="medium" text-case="capitalize-first"/>
        </group>
      </if>
      <!-- Generic labels for specific types -->
      <!-- These should be localized when possible -->
      <else-if type="dataset">
        <text value="Data set"/>
      </else-if>
      <else-if type="book" variable="version" match="all">
        <!-- Replace with type="software" and term="software" as that becomes available -->
        <text value="Computer software"/>
      </else-if>
      <else-if type="interview personal_communication" match="any">
        <choose>
          <if variable="archive container-title DOI publisher URL" match="none">
            <text term="letter" text-case="capitalize-first"/>
          </if>
          <else-if type="interview">
            <text term="interview" text-case="capitalize-first"/>
          </else-if>
        </choose>
      </else-if>
      <else-if type="map">
        <text value="Map"/>
      </else-if>
    </choose>
  </macro>
  <macro name="format-intext">
    <choose>
      <if variable="genre" match="any">
        <text variable="genre" text-case="capitalize-first"/>
      </if>
      <else-if variable="medium">
        <text variable="medium" text-case="capitalize-first"/>
      </else-if>
      <!-- Generic labels for specific types -->
      <!-- These should be localized when possible -->
      <else-if type="dataset">
        <text value="Data set"/>
      </else-if>
      <else-if type="book" variable="version" match="all">
        <!-- Replace with type="software" and term="software" as that becomes available -->
        <text value="Computer software"/>
      </else-if>
      <else-if type="interview personal_communication" match="any">
        <choose>
          <if variable="archive container-title DOI publisher URL" match="none">
            <text term="letter" text-case="capitalize-first"/>
          </if>
          <else-if type="interview">
            <text term="interview" text-case="capitalize-first"/>
          </else-if>
        </choose>
      </else-if>
      <else-if type="map">
        <text value="Map"/>
      </else-if>
    </choose>
  </macro>
  <!-- APA 'source' element contains four parts:
       container, event, publisher, access -->
  <macro name="container">
    <choose>
      <if type="article-journal article-magazine article-newspaper post-weblog review review-book" match="any">
        <!-- Periodical items -->
        <text macro="container-periodical"/>
      </if>
      <else-if type="paper-conference">
        <!-- Determine if paper-conference is a periodical or booklike -->
        <choose>
          <if variable="editor editorial-director collection-editor container-author" match="any">
            <text macro="container-booklike"/>
          </if>
          <else>
            <text macro="container-periodical"/>
          </else>
        </choose>
      </else-if>
      <else-if type="post webpage" match="none">
        <!-- post and webpage treat container-title like publisher -->
        <text macro="container-booklike"/>
      </else-if>
    </choose>
  </macro>
  <macro name="container-periodical">
    <group delimiter=". ">
      <group delimiter=", ">
        <text variable="container-title" font-style="italic" text-case="title"/>
        <choose>
          <if variable="volume">
            <group>
              <text variable="volume" font-style="italic"/>
              <text variable="issue" prefix="(" suffix=")"/>
            </group>
          </if>
          <else>
            <text variable="issue" font-style="italic"/>
          </else>
        </choose>
        <choose>
          <if variable="number">
            <!-- Ex. 6: Journal article with article number or eLocator -->
            <!-- This should be localized -->
            <group delimiter=" ">
              <text term="article-locator" text-case="capitalize-first"/>
              <text variable="number"/>
            </group>
          </if>
          <else>
            <text variable="page"/>
          </else>
        </choose>
      </group>
      <choose>
        <if variable="issued">
          <choose>
            <if variable="issue page volume" match="none">
              <text variable="status" text-case="capitalize-first"/>
            </if>
          </choose>
        </if>
      </choose>
    </group>
  </macro>
  <macro name="container-booklike">
    <choose>
      <if variable="container-title" match="any">
        <group delimiter=" ">
          <text term="in" text-case="capitalize-first"/>
          <group delimiter=", ">
            <names variable="editor translator" delimiter=", &amp; ">
              <!-- Change to editortranslator and move editor to substitute as that becomes available -->
              <name and="symbol" initialize-with=". " delimiter=", "/>
              <label form="short" text-case="title" prefix=" (" suffix=")"/>
              <substitute>
                <names variable="editorial-director"/>
                <names variable="collection-editor"/>
                <names variable="container-author"/>
              </substitute>
            </names>
            <group delimiter=": " font-style="italic">
              <text variable="container-title"/>
              <!-- Replace with volume-title as that becomes available -->
              <choose>
                <if is-numeric="volume" match="none">
                  <group delimiter=" ">
                    <label variable="volume" form="short" text-case="capitalize-first"/>
                    <text variable="volume"/>
                  </group>
                </if>
              </choose>
            </group>
          </group>
          <text macro="parenthetical-container"/>
          <text macro="bracketed-container"/>
        </group>
      </if>
    </choose>
  </macro>
  <macro name="publisher">
    <group delimiter="; ">
      <choose>
        <if type="thesis">
          <choose>
            <if variable="archive DOI URL" match="none">
              <text variable="publisher"/>
            </if>
          </choose>
        </if>
        <else-if type="post webpage" match="any">
          <!-- For websites, treat container title like publisher -->
          <group delimiter="; ">
            <text variable="container-title" text-case="title"/>
            <text variable="publisher"/>
          </group>
        </else-if>
        <else-if type="paper-conference">
          <!-- For paper-conference, don't print publisher if in a journal-like proceedings -->
          <choose>
            <if variable="collection-editor editor editorial-director" match="any">
              <text variable="publisher"/>
            </if>
          </choose>
        </else-if>
        <else-if type="article-journal article-magazine article-newspaper post-weblog" match="none">
          <text variable="publisher"/>
        </else-if>
      </choose>
      <group delimiter=", ">
        <choose>
          <if variable="archive-place">
            <!-- With `archive-place`: physical archives. Without: online archives. -->
            <!-- For physical archives, print the location before the archive name.
                For electronic archives, these are printed in macro="description". -->
            <!-- Split "archive_location" into "archive_collection" and "archive_location" as that becomes available -->
            <!-- Must test for archive_collection:
                With collection: archive_collection (archive_location), archive, archive-place
                No collection: archive (archive_location), archive-place
            -->
            <text variable="archive_location"/>
          </if>
        </choose>
        <text variable="archive"/>
        <text variable="archive-place"/>
      </group>
    </group>
  </macro>
  <macro name="access">
    <choose>
      <if variable="DOI" match="any">
        <text variable="DOI" prefix="https://doi.org/"/>
      </if>
      <else-if variable="URL">
        <group delimiter=" ">
          <choose>
            <if variable="issued status" match="none">
              <group delimiter=" ">
                <text term="retrieved" text-case="capitalize-first"/>
                <date variable="accessed" form="text" suffix=","/>
                <text term="from"/>
              </group>
            </if>
          </choose>
          <text variable="URL"/>
        </group>
      </else-if>
    </choose>
  </macro>
  <macro name="event">
    <choose>
      <if variable="event event-title" match="any">
        <!-- To prevent Zotero from printing event-place due to its double-mapping of all 'place' to
             both publisher-place and event-place. Remove this 'choose' when that is changed. -->
        <choose>
          <if variable="collection-editor editor editorial-director issue page volume" match="none">
            <!-- Don't print event info if published in a proceedings -->
            <group delimiter=", ">
              <text macro="event-title"/>
              <text variable="event-place"/>
            </group>
          </if>
        </choose>
      </if>
    </choose>
  </macro>
  <macro name="event-title">
    <choose>
      <!-- TODO: We expect "event-title" to be used,
           but processors and applications may not be updated yet.
           This macro ensures that either "event" or "event-title" can be accpeted.
           Remove if procesor logic and application adoption can handle this. -->
      <if variable="event-title">
        <text variable="event-title"/>
      </if>
      <else>
        <text variable="event"/>
      </else>
    </choose>
  </macro>
  <!-- After 'source', APA also prints publication history (original publication, reprint info, retraction info) -->
  <macro name="publication-history">
    <choose>
      <if type="patent" match="none">
        <group prefix="(" suffix=")">
          <choose>
            <if variable="references">
              <!-- This provides the option for more elaborate description
                   of publication history, such as full "reprinted" references
                   (examples 11, 43, 44) or retracted references -->
              <text variable="references"/>
            </if>
            <else>
              <group delimiter=" ">
                <text value="Original work published"/>
                <choose>
                  <if is-uncertain-date="original-date">
                    <text term="circa" form="short"/>
                  </if>
                </choose>
                <date variable="original-date">
                  <date-part name="year"/>
                </date>
              </group>
            </else>
          </choose>
        </group>
      </if>
      <else>
        <text variable="references" prefix="(" suffix=")"/>
      </else>
    </choose>
  </macro>
  <!-- Legal citations have their own rules -->
  <macro name="legal-cites">
    <choose>
      <if type="legal_case">
        <group delimiter=". ">
          <group delimiter=", ">
            <text variable="title"/>
            <group delimiter=" ">
              <text macro="container-legal"/>
              <text macro="date-legal"/>
            </group>
            <text variable="references"/>
          </group>
          <text macro="access"/>
        </group>
      </if>
      <else-if type="bill">
        <!-- Currently designed to handle bills, resolutions, hearings, rederal reports. -->
        <group delimiter=". ">
          <group delimiter=", ">
            <choose>
              <if variable="number container-title" match="none">
                <!-- If no number or container-title, then assume it is a hearing -->
                <text variable="title" font-style="italic"/>
              </if>
              <else>
                <text variable="title"/>
              </else>
            </choose>
            <group delimiter=" ">
              <text macro="container-legal"/>
              <text macro="date-legal"/>
              <choose>
                <if variable="number container-title" match="none">
                  <!-- If no number or container-title, then assume it is a hearing -->
                  <names variable="author" prefix="(testimony of " suffix=")">
                    <name and="symbol" delimiter=", "/>
                  </names>
                </if>
                <else>
                  <text variable="status" prefix="(" suffix=")"/>
                </else>
              </choose>
            </group>
            <text variable="references"/>
          </group>
          <text macro="access"/>
        </group>
      </else-if>
      <else-if type="legislation">
        <!-- Currently designed to handle statutes, codified regulations, executive orders.
             For uncodified regulations, assume future code section is in status. -->
        <group delimiter=". ">
          <group delimiter=", ">
            <text variable="title"/>
            <group delimiter=" ">
              <text macro="container-legal"/>
              <text macro="date-legal"/>
              <text variable="status" prefix="(" suffix=")"/>
            </group>
            <text variable="references"/>
          </group>
          <text macro="access"/>
        </group>
      </else-if>
      <else-if type="treaty">
        <!-- APA generally defers to Bluebook for legal citations, but diverges without
             explanation for treaty items. The Bluebook format that was used in APA 6th
             ed. is used here. -->
        <group delimiter=", ">
          <text variable="title" text-case="title"/>
          <names variable="author">
            <name initialize-with="." form="short" delimiter="-"/>
          </names>
          <text macro="date-legal"/>
          <text macro="container-legal"/>
          <text macro="access"/>
        </group>
      </else-if>
    </choose>
  </macro>
  <macro name="date-legal">
    <choose>
      <if type="legal_case">
        <group prefix="(" suffix=")" delimiter=" ">
          <text variable="authority"/>
          <choose>
            <if variable="container-title" match="any">
              <!-- Print only year for cases published in reporters-->
              <date variable="issued" form="numeric" date-parts="year"/>
            </if>
            <else>
              <date variable="issued" form="text"/>
            </else>
          </choose>
        </group>
      </if>
      <else-if type="bill legislation" match="any">
        <group prefix="(" suffix=")" delimiter=" ">
          <group delimiter=" ">
            <date variable="original-date">
              <date-part name="year"/>
            </date>
            <text term="and" form="symbol"/>
          </group>
          <date variable="issued">
            <date-part name="year"/>
          </date>
        </group>
      </else-if>
      <else-if type="treaty">
        <date variable="issued" form="text"/>
      </else-if>
    </choose>
  </macro>
  <macro name="container-legal">
    <!-- Expect legal item container-titles to be stored in short form -->
    <choose>
      <if type="legal_case">
        <group delimiter=" ">
          <choose>
            <if variable="container-title">
              <group delimiter=" ">
                <text variable="volume"/>
                <text variable="container-title"/>
                <group delimiter=" ">
                  <!-- Change to label variable="section" as that becomes available -->
                  <text term="section" form="symbol"/>
                  <text variable="section"/>
                </group>
                <choose>
                  <if variable="page page-first" match="any">
                    <text variable="page-first"/>
                  </if>
                  <else>
                    <text value="___"/>
                  </else>
                </choose>
              </group>
            </if>
            <else>
              <group delimiter=" ">
                <choose>
                  <if is-numeric="number">
                    <!-- Replace with label variable="number" if that becomes available -->
                    <text term="issue" form="short" text-case="capitalize-first"/>
                  </if>
                </choose>
                <text variable="number"/>
              </group>
            </else>
          </choose>
        </group>
      </if>
      <else-if type="bill">
        <group delimiter=", ">
          <group delimiter=" ">
            <text variable="genre"/>
            <group delimiter=" ">
              <choose>
                <if variable="chapter-number container-title" match="none">
                  <!-- Replace with label variable="number" as that becomes available -->
                  <text term="issue" form="short"/>
                </if>
              </choose>
              <text variable="number"/>
            </group>
          </group>
          <text variable="authority"/>
          <text variable="chapter-number"/>
          <group delimiter=" ">
            <text variable="volume"/>
            <text variable="container-title"/>
            <text variable="page-first"/>
          </group>
        </group>
      </else-if>
      <else-if type="legislation">
        <choose>
          <if variable="number">
            <!--There's a public law number-->
            <group delimiter=", ">
              <text variable="number" prefix="Pub. L. No. "/>
              <group delimiter=" ">
                <text variable="volume"/>
                <text variable="container-title"/>
                <text variable="page-first"/>
              </group>
            </group>
          </if>
          <else>
            <group delimiter=" ">
              <text variable="volume"/>
              <text variable="container-title"/>
              <choose>
                <if variable="section">
                  <group delimiter=" ">
                    <!-- Change to label variable="section" as that becomes available -->
                    <text term="section" form="symbol"/>
                    <text variable="section"/>
                  </group>
                </if>
                <else>
                  <text variable="page-first"/>
                </else>
              </choose>
            </group>
          </else>
        </choose>
      </else-if>
      <else-if type="treaty">
        <group delimiter=" ">
          <number variable="volume"/>
          <text variable="container-title"/>
          <choose>
            <if variable="page page-first" match="any">
              <text variable="page-first"/>
            </if>
            <else>
              <group delimiter=" ">
                <!-- Replace with label variable="number" if that becomes available -->
                <text term="issue" form="short" text-case="capitalize-first"/>
                <text variable="number"/>
              </group>
            </else>
          </choose>
        </group>
      </else-if>
    </choose>
  </macro>
  <macro name="citation-locator">
    <group delimiter=" ">
      <choose>
        <if locator="chapter">
          <label variable="locator" text-case="capitalize-first"/>
        </if>
        <else>
          <label variable="locator" form="short"/>
        </else>
      </choose>
      <text variable="locator"/>
    </group>
  </macro>
  <citation et-al-min="3" et-al-use-first="1" disambiguate-add-year-suffix="true" disambiguate-add-names="true" disambiguate-add-givenname="true" collapse="year" givenname-disambiguation-rule="primary-name-with-initials">
    <sort>
      <key macro="author-bib" names-min="3" names-use-first="1"/>
      <key macro="date-sort-group"/>
      <key macro="date-sort-date" sort="ascending"/>
      <key variable="status"/>
    </sort>
    <layout prefix="(" suffix=")" delimiter="; ">
      <group delimiter=", ">
        <text macro="author-intext"/>
        <text macro="date-intext"/>
        <text macro="citation-locator"/>
      </group>
    </layout>
  </citation>
  <bibliography hanging-indent="true" et-al-min="21" et-al-use-first="19" et-al-use-last="true" entry-spacing="0" line-spacing="2">
    <sort>
      <key macro="author-bib"/>
      <key macro="date-sort-group"/>
      <key macro="date-sort-date" sort="ascending"/>
      <key variable="status"/>
      <key macro="title"/>
    </sort>
    <layout>
      <choose>
        <if type="bill legal_case legislation treaty" match="any">
          <!-- Legal items have different orders and delimiters -->
          <choose>
            <if variable="DOI URL" match="any">
              <text macro="legal-cites"/>
            </if>
            <else>
              <text macro="legal-cites" suffix="."/>
            </else>
          </choose>
        </if>
        <else>
          <group delimiter=" ">
            <group delimiter=". " suffix=".">
              <text macro="author-bib"/>
              <text macro="date-bib"/>
              <text macro="title-and-descriptions"/>
              <text macro="container"/>
              <text macro="event"/>
              <text macro="publisher"/>
            </group>
            <text macro="access"/>
            <text macro="publication-history"/>
          </group>
        </else>
      </choose>
    </layout>
  </bibliography>
</style>
<<===== CSL =====<<

>>===== CITATION-ITEMS =====>>
[[  ]]
<<===== CITATION-ITEMS =====<<

>>===== INPUT =====>>
[
  {
    "author": [
      {
        "family": "American College of Sports Medicine",
        "given": ""
      }
    ],
    "citation-key": "americancollegeofsportsmedicine1975",
    "id": "americancollegeofsportsmedicine1975",
    "issued": {
      "date-parts": [
        [
          1975
        ]
      ]
    },
    "title": "Guidelines for graded exercise testing and exercise prescription",
    "type": "book"
  },
  {
    "author": [
      {
        "family": "American College of Sports Medicine",
        "given": ""
      }
    ],
    "citation-key": "americancollegeofsportsmedicine2013",
    "id": "americancollegeofsportsmedicine2013",
    "issued": {
      "date-parts": [
        [
          2013
        ]
      ]
    },
    "title": "ACSM’s resource manual for guidelines for exercise testing and prescription",
    "type": "book"
  },
  {
    "author": [
      {
        "family": "American College of Sports Medicine",
        "given": ""
      }
    ],
    "citation-key": "americancollegeofsportsmedicine2018",
    "id": "americancollegeofsportsmedicine2018",
    "issued": {
      "date-parts": [
        [
          2018
        ]
      ]
    },
    "title": "ACSM’s exercise testing and prescription",
    "type": "book"
  },
  {
    "URL": "https://bit.ly/3DSQHc8",
    "accessed": {
      "date-parts": [
        [
          2021,
          12,
          15
        ]
      ]
    },
    "author": [
      {
        "family": "American College of Sports Medicine",
        "given": ""
      }
    ],
    "citation-key": "americancollegeofsportsmedicine2021",
    "id": "americancollegeofsportsmedicine2021",
    "issued": {
      "date-parts": [
        [
          2021,
          11,
          10
        ]
      ]
    },
    "title": "The American College of Sports Medicine",
    "type": "webpage"
  },
  {
    "author": [
      {
        "family": "American College of Sports Medicine",
        "given": ""
      }
    ],
    "citation-key": "americancollegeofsportsmedicine2021a",
    "id": "americancollegeofsportsmedicine2021a",
    "issued": {
      "date-parts": [
        [
          2021
        ]
      ]
    },
    "title": "ACSM’s guidelines for exercise testing and prescription",
    "type": "book"
  }
]
<<===== INPUT =====<<

>>===== VERSION =====>>
1.0
<<===== VERSION =====<<
jgm commented 1 year ago

Here's the sort key map :

[ ( ItemId { unItemId = "americancollegeofsportsmedicine1975" }
  , [ SortKeyValue
        Ascending
        (Just [ "american" , "college" , "of" , "sports" , "medicine" ])
    , SortKeyValue Ascending (Just [ "1" ])
    , SortKeyValue Ascending (Just [ "1975" ])
    , SortKeyValue Ascending Nothing
    , SortKeyValue
        Ascending
        (Just
           [ "guidelines"
           , "for"
           , "graded"
           , "exercise"
           , "testing"
           , "and"
           , "exercise"
           , "prescription"
           ])
    ]
  )
, ( ItemId { unItemId = "americancollegeofsportsmedicine2013" }
  , [ SortKeyValue
        Ascending
        (Just [ "american" , "college" , "of" , "sports" , "medicine" ])
    , SortKeyValue Ascending (Just [ "1" ])
    , SortKeyValue Ascending (Just [ "2013" ])
    , SortKeyValue Ascending Nothing
    , SortKeyValue
        Ascending
        (Just
           [ "acsm"
           , "s"
           , "resource"
           , "manual"
           , "for"
           , "guidelines"
           , "for"
           , "exercise"
           , "testing"
           , "and"
           , "prescription"
           ])
    ]
  )
, ( ItemId { unItemId = "americancollegeofsportsmedicine2018" }
  , [ SortKeyValue
        Ascending
        (Just [ "american" , "college" , "of" , "sports" , "medicine" ])
    , SortKeyValue Ascending (Just [ "1" ])
    , SortKeyValue Ascending (Just [ "2018" ])
    , SortKeyValue Ascending Nothing
    , SortKeyValue
        Ascending
        (Just
           [ "acsm" , "s" , "exercise" , "testing" , "and" , "prescription" ])
    ]
  )
, ( ItemId { unItemId = "americancollegeofsportsmedicine2021" }
  , [ SortKeyValue
        Ascending
        (Just [ "american" , "college" , "of" , "sports" , "medicine" ])
    , SortKeyValue Ascending (Just [ "1" ])
    , SortKeyValue Ascending (Just [ "11/10/2021" ])
    , SortKeyValue Ascending Nothing
    , SortKeyValue
        Ascending
        (Just
           [ "the" , "american" , "college" , "of" , "sports" , "medicine" ])
    ]
  )
, ( ItemId { unItemId = "americancollegeofsportsmedicine2021a" }
  , [ SortKeyValue
        Ascending
        (Just [ "american" , "college" , "of" , "sports" , "medicine" ])
    , SortKeyValue Ascending (Just [ "1" ])
    , SortKeyValue Ascending (Just [ "2021" ])
    , SortKeyValue Ascending Nothing
    , SortKeyValue
        Ascending
        (Just
           [ "acsm"
           , "s"
           , "guidelines"
           , "for"
           , "exercise"
           , "testing"
           , "and"
           , "prescription"
           ])
    ]
  )
]
jgm commented 1 year ago

OK, we can see the problem:

    , SortKeyValue Ascending (Just [ "11/10/2021" ])

vs

    , SortKeyValue Ascending (Just [ "2021" ])
jgm commented 1 year ago

It's not really clear from the spec, but I see the following:

dates: Date variables called via the variable attribute are returned in the YYYYMMDD format, with zeros substituted for any missing date-parts (e.g. 20001200 for December 2000). As a result, less specific dates precede more specific dates in ascending sorts, e.g. “2000, May 2000, May 1st 2000”. Negative years are sorted inversely, e.g. “100BC, 50BC, 50AD, 100AD”. Seasons are ignored for sorting, as the chronological order of the seasons differs between the northern and southern hemispheres. In the case of date ranges, the start date is used for the primary sort, and the end date is used for a secondary sort, e.g. “2000–2001, 2000–2005, 2002–2003, 2002–2009”. Date ranges are placed after single dates when they share the same (start) date, e.g. “2000, 2000–2002”.

That isn't directly relevant here because we don't have a variable attribute but a macro.

Sorting Macros

The sort key value for a macro called via cs:key via the macro attribute generally consists of the string value the macro would ordinarily generate, without rich text markup (exceptions are discussed below).

OK, so far we're in compliance...

Number variables rendered within the macro with cs:number and date variables are treated the same as when they are called via variable. The only exception is that the complete date is returned if a date variable is called via the variable attribute. In contrast, macros return only those date-parts that would otherwise be rendered (respecting the value of the date-parts attribute for localized dates, or the listing of cs:date-part elements for non-localized dates).

This doesn't really clear things up for me. But clearly what would make this work is if we returned something like 20211110; that must be what's intended.

jgm commented 1 year ago

ok, I think I've got this fixed. Thanks for reporting!