jgm/citeproc

Name variable cleared rather than suppressed after use in substitution

alex-ball opened this issue · 13 comments

I am using citeproc 0.6.0.1 via pandoc 2.17.1.1 on Linux.

In a CSL citation style you typically get something like this, with name substitution:

<macro name="author">
  <names variable="author">
    <substitute>
      <names variable="editor"/>
    </substitute>
  </names>
</macro>

In an entry with an editor but no author, if the style runs the test <if variable="editor"> before this macro it returns true, but if the test runs after this macro it returns false. This behaviour does not match the behaviour of the <if> test when the name variable is used directly, and as far as I can see with citeproc-js it returns true both times.

I know the spec says "Substituted variables are suppressed in the rest of the output to prevent duplication. Substituted variables are considered empty for the purposes of determining whether to suppress an enclosing cs:group" but I don't think this implies it should be considered empty for the purposes of the <if> test.

Attached are some files that constitute a reasonably minimal working example that I ran with

pandoc -o test-doc.html --citeproc --csl test-style.csl --bibliography=refs.yaml test-doc.md

Expected output:

NO_AUTHOR EDITOR Haynes, W.M., ed. NO_AUTHOR EDITOR, 2014...

Actual output:

NO_AUTHOR EDITOR Haynes, W.M., ed. NO_AUTHOR NO_EDITOR, 2014...

The second (Blockley) reference is just to demonstrate that the <if> test gives a consistent answer when names are printed normally.

substitute-name-test.zip

jgm commented

The relevant code is at src/Citeproc/Eval.hs l. 1643:

      handleSubst :: Eval a ()                                   
      handleSubst = do inSubst <- asks contextInSubstitute     
                       when inSubst $                       
                         modify $ \st -> -- delete variable so it isn't used again...                                                
                           st{ stateReference =        
                                 let Reference id' type' d' m' = stateReference st                                        
                                  in Reference id' type' d' (M.delete v m') }
jgm commented

We need to do something fancier; maybe a separate state field to indicate which variables are substituted, which we check when considering whether to suppress an enclosing group.

jgm commented

@bdarcus do you agree with this interpretation of the spec?

Let's also involve @bwiernik. And let's also hear the opinions of other implementors @cormacrelf, @fbennett, @retorquere.

And for reference, there is also a long discussion about cs:substitute.

To explain why this matters to me: I maintain a style where it matters whether the title is printed in its normal position or at the head of the reference. With other implementations (including pandoc-citeproc) I can use <if variable="author editor" match="any"> to work this out. If I have misunderstood and this was only working by accident, then I suppose I will have to reimplement <substitute> as a chain of <choose> elements; but from the linked thread I see I'm not alone in my interpretation (unless this changed with v1.0.2).

I don't think this has changed. Such a change might only be introduced in a bigger update.

I think I agree that a suppressed variable should not be treated as empty. The major case that comes to mind is something like "if a book has a series editor, format it one way, otherwise format it another way". I think that citeproc-js does not treat substituted variables as empty.

@alex-ball I'm not understanding your use case though. In your case, it seems like you can just add title to the author substitute, like what is done in APA.CSL

@bwiernik I do add title to the author substitute. In this style there are, lets say, some organically grown rules for where to place an "[Online]" label for online resources; for some (but not all) entry types it is placed after the title, which is normally after the date but might be at the head of the reference as discussed. Hence I need to know in which position it is printed, so I can put this online label in the right place.

I would do that by making a macro for the title that contains the Online logic. Then put that macro in substitute. apa.csl has an example of that too

@bwiernik The somewhat different macros for the title in normal position and the title in substitute are already quite complicated but I'll see what refactoring can be done.

Sorry for diverting this thread into unrelated territory when the point was more about consistency of behaviour across implementations.

Feel free to send me a message with your style and I can offer some thoughts

jgm commented

I've merged my changes from the issue101 branch and added a test based on the case above.
I think this issue can now be closed, but please test and let me know if anything is missing.