Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

The delimiter attribute of <group> is not applied to items inside <choose> #180

Open
csimide opened this issue Jun 11, 2024 · 2 comments · May be fixed by #269
Open

The delimiter attribute of <group> is not applied to items inside <choose> #180

csimide opened this issue Jun 11, 2024 · 2 comments · May be fixed by #269

Comments

@csimide
Copy link

csimide commented Jun 11, 2024

Consider the following CSL snippet:

<group delimiter=". ">
  <text value="v0"/> 
  <text value="v1"/>
  <choose>
    <if type="book">
      <text value="v2"/>
      <text value="v3"/>
    </if>
  </choose>
</group>
The complete test CSL file
<?xml version="1.0" encoding="utf-8"?>
<style xmlns="http://purl.org/net/xbiblio/csl" version="1.0" class="in-text" name-as-sort-order="all" sort-separator=" " demote-non-dropping-particle="never" initialize-with=" " initialize-with-hyphen="false" page-range-format="expanded" default-locale="zh-CN">
  <info>
    <title>test</title>
    <id>http://test</id>
    <category citation-format="numeric"/>
    <category field="generic-base"/>
  </info>
  <macro name="entry-layout">
    <group delimiter=". ">
      <text value="v0"/> 
      <text value="v1"/>
      <choose>
        <if type="book">
          <text value="v2"/>
          <text value="v3"/>
        </if>
      </choose>
    </group>
  </macro>
  <citation collapse="citation-number" after-collapse-delimiter=",">
    <sort>
      <key variable="citation-number"/>
    </sort>
    <layout vertical-align="sup" delimiter="," prefix="[" suffix="]">
      <text variable="citation-number"/>
    </layout>
  </citation>
  <bibliography>
    <layout>
      <text variable="citation-number" prefix="[" suffix="]"/>
      <text macro="entry-layout"/>
    </layout>
  </bibliography>
</style>

Expected reference output: v0. v1. v2. v3
Actual reference output in Typst: v0. v1. v2v3

image

I noticed that when <group> contains <choose>, the group delimiter is not applied to elements inside <choose>. Instead, <choose> is treated as a group without a delimiter.

This behavior is inconsistent with reference management software like Zotero. In the CSL 1.0.2 documentation, it is stated:

Delimiters from the nearest delimiting element are applied within the output of cs:choose (i.e., the output of the matching cs:if, cs:else-if, or cs:else; see delimiter).

src: https://docs.citationstyles.org/en/stable/specification.html#choose


P.S. Currently, this issue can be mitigated by nesting <group delimiter=". "> inside <choose>. However, this means that additional modifications to the CSL are required for it to work with Typst.

Example
<group delimiter=". ">
  <text value="v0"/> 
  <text value="v1"/>
  <choose>
    <if type="book">
      <group delimiter=". "> <!-- Add a nested group -->
        <text value="v2"/>
        <text value="v3"/>
      </group>  <!-- Add a nested group -->
    </if>
  </choose>
</group>
@YDX-2147483647
Copy link

YDX-2147483647 commented Jan 2, 2025

Background information

This issue affects GB/T 7714—2015 (gb-7714-2015-numeric etc.). Typst v0.12.0 generates New YorkMcGraw Hill instead of New York: McGraw Hill.

Real usage of <choose> inside <group delimiter>:
https://github.com/citation-style-language/styles/blob/080516e27470d03c70bd3d5f6d712a0b61a45448/china-national-standard-gb-t-7714-2015-numeric.csl#L297-L309

Relates-to: #189, #109 (comment)

(Sorry to bother you, but I hope the above will help people find this issue, and finally get it fixed.)

@YDX-2147483647
Copy link

YDX-2147483647 commented Jan 21, 2025

Test fixture
>>===== MODE =====>>
citation
<<===== MODE =====<<


>>===== DESCRIPTION =====>>
Delimiters from the nearest delimiters from the nearest ancestor delimiting element (e.g., <group>)
are applied within the output of <choose>
(i.e., the output of the matching <if>, <else-if>, or <else>).
https://docs.citationstyles.org/en/stable/specification.html#choose

But they are not applied within the output of a delimiting element or a <text macro="…"> element.
https://docs.citationstyles.org/en/stable/specification.html#delimiter
https://docs.citationstyles.org/en/stable/specification.html#macro

https://github.com/typst/hayagriva/issues/180
<<===== DESCRIPTION =====<<


>>===== RESULT =====>>
Title[-]Edition[-]Publisher[-]Place[-]PublisherPlace
<<===== RESULT =====<<


>>===== INPUT =====>>
[
    {
        "edition": "Edition",
        "id": "random",
        "publisher": "Publisher",
        "publisher-place": "Place",
        "title": "Title",
        "type": "book"
    }
]
<<===== INPUT =====<<


>>===== CSL =====>>
<?xml version="1.0" encoding="utf-8"?>
<style xmlns="http://purl.org/net/xbiblio/csl" version="1.0" class="in-text">
  <info>
    <id />
    <title />
  </info>
  <macro name="unaffected">
    <text variable="publisher"/>
    <text variable="publisher-place"/>
  </macro>
  <citation>
    <layout>
      <group delimiter="[-]">
        <text variable="title"/> 
        <text variable="edition"/>
        <choose>
          <if type="book">
            <text variable="publisher"/>
            <text variable="publisher-place"/>
          </if>
        </choose>
        <text macro="unaffected"/>
      </group>
    </layout>
  </citation>
</style>
<<===== CSL =====<<


>>===== VERSION =====>>
1.0.2
<<===== VERSION =====<<

A dirty fix

LayoutRenderingElement::Choose(choose) => choose.render(ctx),

Change the above line to the following.

            LayoutRenderingElement::Choose(choose) => {
                assert_eq!(choose.delimiter, None);
                let choose = citationberg::Choose {
                    // Use the parent's delimiter
                    delimiter: delimiter.map(|s| s.to_string()),
                    // Clone all branches
                    if_: choose.if_.clone(),
                    else_if: choose.else_if.clone(),
                    otherwise: choose.otherwise.clone(),
                };
                choose.render(ctx)
            }

Definitely not desirable, but all current tests pass.

Related discussion on CSL

Tests affected in https://github.com/citation-style-language/test-suite/tree/d2bd47ff09db6e2995aeed2be0b096b12c0f8f70/processor-tests

Compact list
Generated by a script
import json
from pathlib import Path
from xml.etree import ElementTree as ET

BASE_URL = (
    "https://github.com/citation-style-language/test-suite/tree/master/processor-tests/"
)
TEST_DIR = Path("target/haya-cache/test-suite/processor-tests")
PASSED_TESTS = Path("tests/citeproc-pass.txt").read_text(encoding="utf-8").splitlines()

ns = {"cs": "http://purl.org/net/xbiblio/csl"}
ET.register_namespace("", ns["cs"])  # for `ET.tostring`

for file in (TEST_DIR / "machines").iterdir():
    root = ET.fromstring(json.loads(file.read_text(encoding="utf-8"))["csl"])

    # <if> under <group delimiter> containing more than direct children
    results = root.findall(".//cs:group[@delimiter]/cs:choose/cs:if/*[2]/../../..", ns)

    if results:
        human = TEST_DIR / "humans" / file.with_suffix(".txt").name
        assert human.exists()

        print(
            f"#### [{human.stem}]({BASE_URL + human.relative_to(TEST_DIR).as_posix()}) — {len(results)} matches, test: {'✅' if human.stem in PASSED_TESTS else '❌'}",
            end="\n\n",
        )

        for r in results:
            print("```xml")
            print(ET.tostring(r, encoding="unicode"))
            print("```", end="\n\n")
Full list

affix_WithCommas — 1 matches, test: ❌

<group xmlns="http://purl.org/net/xbiblio/csl" delimiter=", ">
          <choose>
            <if variable="author">
              <choose>
                <if variable="container-author">
                  <names variable="container-author">
                    <label form="verb-short" text-case="lowercase" suffix=" " />
                    <name and="text" delimiter=", " />
                  </names>
                </if>
              </choose>
              
              <choose>
                <if variable="container-author author" match="all">
                  <group delimiter=". ">
                    <text variable="page" />
                    <names variable="editor translator" delimiter=", ">
                      <label form="verb" suffix=" " />
                      <name and="text" delimiter=", " />
                </group>
                </if>
                <else>
                  <names variable="editor translator" delimiter=", ">
                    <label form="verb" text-case="lowercase" suffix=" " />
                    <name and="text" delimiter=", " />
                  </names>
                </else>
              </choose>
            </if>
          </choose>
        </group>
      

bugreports_AuthorPosition — 1 matches, test: ❌

<group xmlns="http://purl.org/net/xbiblio/csl" delimiter=" " prefix=", ">
          <choose>
            <if variable="container-title">
              <text variable="volume" />
              <text variable="container-title" />
              <group delimiter=" ">
                
                <text term="section" form="symbol" />
                <text variable="section" />
              </group>
              <text variable="page" />
            </if>
            <else>
              <choose>
                <if type="legal_case">
                  <text variable="number" prefix="No. " />
                </if>
                <else>
                  <text variable="number" prefix="Pub. L. No. " />
                  <group delimiter=" ">
                    
                    <text term="section" form="symbol" />
                    <text variable="section" />
                  </group>
                </else>
              </choose>
            </else>
          </choose>
        </group>
      

date_AccessedCrash — 2 matches, test: ❌

<group xmlns="http://purl.org/net/xbiblio/csl" prefix=", " delimiter=" ">
          <choose>
            <if variable="container-title">
              <text variable="volume" />
              <text variable="container-title" />
              <group delimiter=" ">
                <text term="section" form="symbol" />
                <text variable="section" />
              </group>
              <text variable="page" />
            </if>
            <else>
              <text variable="number" prefix="No. " />
            </else>
          </choose>
        </group>
      
<group xmlns="http://purl.org/net/xbiblio/csl" delimiter=", " prefix=", ">
          <choose>
            <if variable="number">
              <text variable="number" prefix="Pub. L. No. " />
              <group delimiter=" ">
                <text term="section" form="symbol" />
                <text variable="section" />
              </group>
              <group delimiter=" ">
                <text variable="volume" />
                <text variable="container-title" />
                <text variable="page-first" />
              </group>
            </if>
            <else>
              <group delimiter=" ">
                <text variable="volume" />
                <text variable="container-title" />
                <text term="section" form="symbol" />
                <text variable="section" />
              </group>
            </else>
          </choose>
        </group>
      

date_DisappearingBug — 2 matches, test: ✅

<group xmlns="http://purl.org/net/xbiblio/csl" prefix=", " delimiter=" ">
          <choose>
            <if variable="container-title">
              <text variable="volume" />
              <text variable="container-title" />
              <group delimiter=" ">
                
                <text term="section" form="symbol" />
                <text variable="section" />
              </group>
              <text variable="page" />
            </if>
            <else>
              <text variable="number" prefix="No. " />
            </else>
          </choose>
        </group>
      
<group xmlns="http://purl.org/net/xbiblio/csl" delimiter=", " prefix=", ">
          <choose>
            <if variable="number">
              
              <text variable="number" prefix="Pub. L. No. " />
              <group delimiter=" ">
                
                <text term="section" form="symbol" />
                <text variable="section" />
              </group>
              <group delimiter=" ">
                <text variable="volume" />
                <text variable="container-title" />
                <text variable="page-first" />
              </group>
            </if>
            <else>
              <group delimiter=" ">
                <text variable="volume" />
                <text variable="container-title" />
                
                <text term="section" form="symbol" />
                <text variable="section" />
              </group>
            </else>
          </choose>
        </group>
      

flipflop_Apostrophes — 1 matches, test: ❌

<group xmlns="http://purl.org/net/xbiblio/csl" delimiter=", ">
          <choose>
            <if variable="author">
              <choose>
                <if variable="container-author">
                  <names variable="container-author">
                    <label form="verb-short" text-case="lowercase" suffix=" " />
                    <name and="text" delimiter=", " />
                  </names>
                </if>
              </choose>
              
              <choose>
                <if variable="container-author author" match="all">
                  <group delimiter=". ">
                    <text variable="page" />
                    <names variable="editor translator" delimiter=", ">
                      <label form="verb" suffix=" " />
                      <name and="text" delimiter=", " />
                    </names>
                  </group>
                </if>
                <else>
                  <names variable="editor translator" delimiter=", ">
                    <label form="verb" text-case="lowercase" suffix=" " />
                    <name and="text" delimiter=", " />
                  </names>
                </else>
              </choose>
            </if>
          </choose>
        </group>
      

label_NameLabelThroughSubstitute — 2 matches, test: ❌

<group xmlns="http://purl.org/net/xbiblio/csl" delimiter=" ">
            <choose>
              <if variable="container-title">
                <text variable="volume" />
                <text variable="container-title" />
                <group delimiter=" ">
                  
                  <text term="section" form="symbol" />
                  <text variable="section" />
                </group>
                <text variable="page" />
              </if>
              <else>
                <group delimiter=" ">
                  <choose>
                    <if is-numeric="number">
                      
                      <text term="issue" form="short" text-case="capitalize-first" />
                    </if>
                  </choose>
                  <text variable="number" />
                </group>
              </else>
            </choose>
          </group>
          
<group xmlns="http://purl.org/net/xbiblio/csl" delimiter=", ">
            <choose>
              <if variable="number">
                
                <text variable="number" prefix="Pub. L. No. " />
                <group delimiter=" ">
                  
                  <text term="section" form="symbol" />
                  <text variable="section" />
                </group>
                <group delimiter=" ">
                  <text variable="volume" />
                  <text variable="container-title" />
                  <text variable="page-first" />
                </group>
              </if>
              <else>
                <group delimiter=" ">
                  <text variable="volume" />
                  <text variable="container-title" />
                  
                  <text term="section" form="symbol" />
                  <text variable="section" />
                </group>
              </else>
            </choose>
          </group>
          

number_NewOrdinalsEdition — 1 matches, test: ❌

<group xmlns="http://purl.org/net/xbiblio/csl" delimiter=", ">
          <choose>
            <if variable="author">
              <choose>
                <if variable="container-author">
                  <names variable="container-author">
                    <label form="verb-short" text-case="lowercase" suffix=" " />
                    <name and="text" delimiter=", " />
                  </names>
                </if>
              </choose>
              
              <choose>
                <if variable="container-author author" match="all">
                  <group delimiter=". ">
                    <text variable="page" />
                    <names variable="editor translator" delimiter=", ">
                      <label form="verb" suffix=" " />
                      <name and="text" delimiter=", " />
                    </names>
                  </group>
                </if>
                <else>
                  <names variable="editor translator" delimiter=", ">
                    <label form="verb" text-case="lowercase" suffix=" " />
                    <name and="text" delimiter=", " />
                  </names>
                </else>
              </choose>
            </if>
          </choose>
        </group>
      

position_NearNoteWithPlugin — 4 matches, test: ❌

<group xmlns="http://purl.org/net/xbiblio/csl" delimiter=" ">
			<choose>
			  <if variable="issue">
				<text variable="volume" prefix="[" suffix="]" />
				<text variable="issue" />
			  </if>
			  <else>
				<text variable="volume" />
			  </else>
			</choose>
			<text variable="container-title" form="short" />
			<group>
			  <text variable="page" />
			  <text macro="bb-point-locator-comma" />
			</group>
			<group prefix="(" suffix=")" delimiter=" ">
			  <text variable="authority" form="short" />
			  <date variable="issued">
				<date-part name="year" />	
			  </date>
			</group>	
		  </group>
		
<group xmlns="http://purl.org/net/xbiblio/csl" delimiter=" ">
		<choose>
		  <if variable="issue">
			<text variable="volume" prefix="[" suffix="]" />
			<text variable="issue" />
		  </if>
		  <else>
			<text variable="volume" />
		  </else>
		</choose>
        <text variable="container-title" form="short" />
		<choose>
          <if variable="locator">
            <text macro="bb-point-locator-base" />
		  </if>
		  <else>
		    <text variable="page" />
		  </else>
		</choose>
      </group>
	
<group xmlns="http://purl.org/net/xbiblio/csl" delimiter=" ">
		<text variable="volume" />
		<text variable="container-title" />
		<text variable="number" />
		<text variable="page" />
		<choose>
		  <if is-numeric="section">
			<text term="section" form="symbol" />
			<text variable="section" />
		  </if>
		</choose>
	  </group>
	  
<group xmlns="http://purl.org/net/xbiblio/csl" delimiter=" ">
		  <text value="supra" font-style="italic" />
		  <choose>
			<if variable="first-reference-note-number">
			  <text value="note" />
			  <text variable="first-reference-note-number" />
			</if>
		  </choose>
		</group>
        

quotes_PunctuationNasty — 1 matches, test: ❌

<group xmlns="http://purl.org/net/xbiblio/csl" delimiter=", ">
          <choose>
            <if variable="author">
              <choose>
                <if variable="container-author">
                  <names variable="container-author">
                    <label form="verb-short" text-case="lowercase" suffix=" " />
                    <name and="text" delimiter=", " />
                  </names>
                </if>
              </choose>
              
              <choose>
                <if variable="container-author author" match="all">
                  <group delimiter=". ">
                    <text variable="page" />
                    <names variable="editor translator" delimiter=", ">
                      <label form="verb" suffix=" " />
                      <name and="text" delimiter=", " />
                    </names>
                  </group>
                </if>
                <else>
                  <names variable="editor translator" delimiter=", ">
                    <label form="verb" text-case="lowercase" suffix=" " />
                    <name and="text" delimiter=", " />
                  </names>
                </else>
              </choose>
            </if>
          </choose>
        </group>
      

sort_LeadingA — 1 matches, test: ❌

<group xmlns="http://purl.org/net/xbiblio/csl" delimiter=", ">
          <choose>
            <if variable="author">
              <choose>
                <if variable="container-author" match="any">
                  <names variable="container-author">
                    <label form="verb-short" text-case="lowercase" suffix=" " />
                    <name and="text" delimiter=", " />
                  </names>
                </if>
              </choose>
              
              <choose>
                <if variable="container-author author" match="all">
                  <group delimiter=". ">
                    <text variable="page" />
                    <names variable="editor translator" delimiter=", ">
                      <label form="verb" suffix=" " />
                      <name and="text" delimiter=", " />
                    </names>
                  </group>
                </if>
                <else>
                  <names variable="editor translator" delimiter=", ">
                    <label form="verb" text-case="lowercase" suffix=" " />
                    <name and="text" delimiter=", " />
                  </names>
                </else>
              </choose>
            </if>
          <  

textcase_RepeatedTitleBug — 2 matches, test: ❌

<group xmlns="http://purl.org/net/xbiblio/csl" prefix=", " delimiter=" ">
          <choose>
            <if variable="container-title">
              <text variable="volume" />
              <text variable="container-title" />
              <group delimiter=" ">
                
                <text term="section" form="symbol" />
                <text variable="section" />
              </group>
              <text variable="page" />
            </if>
            <else>
              <text variable="number" prefix="No. " />
            </else>
          </choose>
        </group>
      
<group xmlns="http://purl.org/net/xbiblio/csl" delimiter=", " prefix=", ">
          <choose>
            <if variable="number">
              
              <text variable="number" prefix="Pub. L. No. " />
              <group delimiter=" ">
                
                <text term="section" form="symbol" />
                <text variable="section" />
              </group>
              <group delimiter=" ">
                <text variable="volume" />
                <text variable="container-title" />
                <text variable="page-first" />
              </group>
            </if>
            <else>
              <group delimiter=" ">
                <text variable="volume" />
                <text variable="container-title" />
                
                <text term="section" form="symbol" />
                <text variable="section" />
              </group>
            </else>
          </choose>
        </group>
      

YDX-2147483647 added a commit to YDX-2147483647/hayagriva that referenced this issue Jan 22, 2025
Fixes typst#180

A design trade-off:
The delimiter stack uses `String` instead of `&str`.
Using `&str` could eliminate many cloning, but at the cost of introducing complex lifetimes.
Considering that delimiters are typically short, I choose `String`.
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

Successfully merging a pull request may close this issue.

2 participants