seboettg / citeproc-php

Full-featured CSL 1.0.1 processor for PHP
MIT License
75 stars 39 forks source link

Iteratively render bibliography items #48

Closed OleVik closed 6 years ago

OleVik commented 6 years ago

In regards to an example for an older version, you could iterate over items. Is this no longer possible in v2.1.1? An error is thrown saying "No valid format for variable data. Either DataList or array expected".

In all other respects, the bibliography renders as expected, but overriding the HTML-ouput is made much more difficult with no easy access to raw keys, citations or bibliographies per item.

seboettg commented 6 years ago

In regards to an example for an older version, you could iterate over items. Is this no longer possible in v2.1.1? An error is thrown saying "No valid format for variable data. Either DataList or array expected".

CSL supports sorting of bibliography items. In order to enable this feature citeproc has to get the whole list of bibliography items. The bibliography function of citeproc expects an array. Therefore you don't have to care about iterations.

In all other respects, the bibliography renders as expected, but overriding the HTML-ouput is made much more difficult with no easy access to raw keys, citations or bibliographies per item.

You can use lambda functions to override HTML output as described here.

seboettg commented 6 years ago

The citation key (or raw key as you've called) is ( – according to the CSL specification – ) a property of the item, called id.

in your grav plugin you do something like this:

foreach ($data as $key => $item) {
    $biblio .= '[^' . $key . ']: ' . $citeProc->render($item) . "\n";
}

As described above, you can use Lambda functions:

$func = function($cslItem, $renderedText) {
    return '[^' . $cslItem->id . ']: ' . $renderedText;
}
$citeProc = new CiteProc($style, "en-US", $func);
$biblio = $citeProc->render(json_decode($data), "bibliography");
...

I guess this should work for your use case. Of course, you need the id property in your citation items.

OleVik commented 6 years ago

This comes very close to my use case, which as you divined is to update the plugin to use this rather than the deprecated AcademicPuma-library.

However, the custom lambda functions can only be applied to CSL-variables or csl-entry, which is hardcoded along with csl-bib-body in Layout.php. Using csl-entry works to create the Markdown for each item, but the HTML-structure remains.

I tried passing the lambda-function as the third parameter as you suggest, but it would only altar the output if passed by reference from an array of variables to override - like in the example in the readme.

seboettg commented 6 years ago

I guess, I don't understand the problem. What do you want to do exactly, or more specifically what kind of output do you expect from citeproc-php?

OleVik commented 6 years ago

I want to strip out the default enclosing HTML, specifically csl-bib-body (in Layout.php) and csl-entry (also in Layout.php), and then generate the requisite Markdown-formatting around each entry so it can be used as a footnote.

Currently, I achieve this by entirely overriding Layout.php through Composer, but it should seemingly be possible with the lambda-functions. However, when I try to pass the $func from above as the parameter to CiteProc, the output is not altered. This appears to be because the lambda-functions must be passed with an accompanying key that matches a CSL-variable, as per the Good to know-section of the readme.

seboettg commented 6 years ago

If I understand you correctly, then you mean simply use strip_tags within of your custom lambda function as follows:

$func = [
    "bibliography" => [
        "csl-entry" = function($cslItem, $renderedText) {
            return '[^' . $cslItem->id . ']: ' . strip_tags($renderedText);
        }
    ]
];
$citeProc = new CiteProc($style, "en-US", $func);
$biblio = $citeProc->render(json_decode($data), "bibliography");

This won't work, because the lambda function will be executed before the tag will be wrapped around the output. Did you try to use strip_tags for the whole render result, as follows:

$biblio = $citeProc->render(json_decode($data), "bibliography");
$output = strip_tags($biblio);

Another approach (similar to your usage of the old citeproc-php version) would be a good workaround:

$func = [
    "bibliography" => [
        "csl-entry" = function($cslItem, $renderedText) {
            return '[^' . $cslItem->id . ']: ' . $renderedText;
        }
    ]
];

foreach ($data as $key => $item) {
    $citeProc = new CiteProc($style, "en-US", $func);
    $biblio .= '[^' . $key . ']: ' . strip_tags($citeProc->render([$item])) . "\n";
}

Be aware, using this approach CSL sorting will not work.

OleVik commented 6 years ago

Both of these approaches will yield the desired output, though an option to override the hardcoded HTML would be preferable.

That is, the level of customizability would be improved by being able to control the wrappers as well as the content, such that the package can be used as an underlying library in a variety of use-cases.

I will use the first approach when releasing an update to the Grav-plugin, thank you for taking the time to help me understand the implementation.