Is there a way to add URIs to an export field? (bib translator)

I am looking at my data, and I would like to be able to export the linked URI's as a field that I can then put in my citations instead of the URL field.

That way, with my bibtex file looking like this:

@article{editorIfWerePresident2019,
title = {``{{If I Were President Putin}}\ldots '': {{How}} to {{Reduce}} the {{Amount}} of {{Divorces}}},
author = {{editor}},
year = {2019},
month = mar,
url = {https://blog.obitel-minsk.com/2019/03/if-i-were-president-putin-how-to-reduce-the-amount-of-divorces.html},
collaborator = {Smirnov, Dimitry},
journal = {The Catalogue of Good Deeds}
}

I would then have another field of:
URI_Name = {URI_link}

For this particular document, it would be:
site pdf english = https://serversite.com/etc./etc./

I noticed the RDF translator can see this info, and I'm wondering if there's a way to make my bibtex (or a copy of my bibtex) have these fields as well?

The end goal is to be able to call these fields in LaTeX so that when I make the pdf, I don't give away my collected primary sources (the url above), but my fellow researchers can click the link to our server and read our saved copy of the source.
  • edited June 24, 2020
    edit: It looks like I can edit my bibtex exporter in the fieldMap section, but so far if I do:

    attachments: "attachments",

    it exports:
    attachments = {[object Object],[object Object]},

    I don't write java, mostly python, so I'm not really sure how to access these objects. I tried attachments["title"] and got an error on export.

    edit2: I guess I can't edit it necessarily in that fieldMap section. I think I would have to put another if statement here:

    if (item.attachments) {
    var attachmentString = "";

    for (let i = 0; i < item.attachments.length; i++) {
    var attachment = item.attachments[i];
    if (Zotero.getOption("exportFileData") && attachment.saveFile) {
    attachment.saveFile(attachment.defaultPath, true);
    attachmentString += ";" + encodeFilePathComponent(attachment.title) + ":"
    + encodeFilePathComponent(attachment.defaultPath) + ":"
    + encodeFilePathComponent(attachment.mimeType);
    }
    else if (attachment.localPath) {
    attachmentString += ";" + encodeFilePathComponent(attachment.title) + ":"
    + encodeFilePathComponent(attachment.localPath) + ":"
    + encodeFilePathComponent(attachment.mimeType);
    }
    }

    if (attachmentString) {
    writeField("file", attachmentString.substr(1));
    }
    }

    something that doesnt require me to have selected export files option, but will still access the attachment URIs and titles hopefully with attachment.url and attachment.title since I see those on scaffold.
  • If anyone was wondering, I fixed it by adding this before the final newline write:

    if (item.attachments) {
    Zotero.write(",");
    for (let i = 0; i < item.attachments.length; i++){
    var attachment = item.attachments[i];
    var temp_title = "";
    Zotero.write("\n");
    if (attachment.title){
    temp_title = attachment.title.replace(/ /g, "");
    }
    Zotero.write("\t" + temp_title + " " + "=" + " ");
    Zotero.write("{" + attachment.url + "}" + ",");
    }
    }

  • That will get overwritten when the Zotero bibtex translator is ever updated. You can do this in a way that won't get overwritten using https://retorque.re/zotero-better-bibtex/installation/preferences/advanced/#postscript
  • Thanks for the tip, but if I put my code snippet into postscript: I guess it doesn't know what the variables are to make it work, I think the item.attachments isn't known now?

    Current code snippet is this:
    if (item.attachments) {
    Zotero.write(",");
    for (let i = 0; i < item.attachments.length; i++){
    var attachment = item.attachments[i];
    if (attachment.title.includes("site")){
    Zotero.write("\n");
    if (attachment.title.includes("russian")){
    Zotero.write("\t" + "pdfsiterussian" + " " + "=" + " ");
    Zotero.write("{" + attachment.url + "}" + ",");
    }
    else{
    Zotero.write("\t" + "pdfsiteenglish" + " " + "=" + " ");
    Zotero.write("{" + attachment.url + "}" + ",");
    }

    }
    }
    }
  • It does have them, but doesn't use Zotero.write: https://retorque.re/zotero-better-bibtex/exporting/scripting/ . The postscript would be either:

    if (Translator.BetterTeX && item.attachments) {
    for (const name of ['pdfsiterussian', 'pdfsiteenglish']) {
    reference.add({
    name: name,
    value: item.attachments
    .filter(att => att.url && (name === 'pdfsiterussian' ? att.title.includes('russian') : !att.title.includes('russian')))
    .map(att => att.url)
    .join('; '),
    enc: 'verbatim'
    })
    }
    }


    or

    if (Translator.BetterTeX && item.attachments) {
    for (const name of ['pdfsiterussian', 'pdfsiteenglish']) {
    const bibtex = item.attachments
    .filter(att => att.url && (name === 'pdfsiterussian' ? att.title.includes('russian') : !att.title.includes('russian')))
    .map(att => att.url)
    .join('; ')
    if (bibtex) reference.add({ name: name, bibtex: '{' + bibtex + '}' })
    }
    }


    depending on whether you want BBT to handle the character mapping or just trust that URLs are valid bibtex.


  • edited June 25, 2020
    It kind of works. It's grabbing more than needed for the other links that don't contain russian.

    The output ends up looking like this:
    pdfsiterussian = {website/s/iez38d36uywu606ue52dngad3vky8h4e},
    pdfsiteenglish = {website/s/huvknixkfqq570u6qlsjiez5sx6e08qq; website/s/ppzdlh3v8t6g6jju94gcf90ul2fijyon; website/s/585sq485v52z1c2r03i6tq123dvgs3bz; website//utexas.box.com/s/gmn2pd08iy7s9a8n6blb2vvad59u4ekc}

    I assume there's a way to if statement the single link to where if it contains 'russian' and 'site' it only returns the URI of that result, while if it contains 'english' and 'site' it only returns that URI.
  • edited June 25, 2020
    Okay think I got it working with some spaghetti:

    I also wish there was a post somewhere on zotero about formatting....

    if (Translator.BetterTeX && item.attachments) {
    for (const name of ['pdfsiterussian', 'pdfsiteenglish']) {
    if (name === 'pdfsiterussian'){
    reference.add({
    name: name,
    value: item.attachments
    .filter(att => att.url && (name === 'pdfsiterussian' ? att.title.includes('russian' && 'site') : !att.title.includes('russian')))
    .map(att => att.url)
    .join('; '),
    enc: 'verbatim'
    })
    } else{
    reference.add({
    name: name,
    value: item.attachments
    .filter(att => att.url && (name === 'pdfsiteenglish' ? att.title.includes('english' && 'site') : !att.title.includes('english')))
    .map(att => att.url)
    .join('; '),
    enc: 'verbatim'
    })
    }
    }
    }
  • That code can't work. 'russian' && 'site' is a boolean expression where the operands are evaluated as truthy or falsy; 'russian' and 'site' are truthy, so 'russian' && 'site' will yield 'site', so that filter will pick out any title that contains 'site', and will not look at 'russian' at all.

    Do you want to filter on titles that contain both 'russian' and 'site'? Then something like this should do the job:

    if (Translator.BetterTeX && item.attachments) {
    for (const lang of ['russian', 'english']) {
    reference.add({
    name: `pdfsite${lang}`,
    value: item.attachments.filter(att.url => att.url && att.title.includes('site') && att.title.includes(lang)).map(att => att.url)[0],
    enc: 'verbatim',
    })
    }
    }


    in javascript, array access beyond the end of the array yields undefined without further errors or warnings, so if the filter/map finds nothing, acessing 0 will return undefined. reference.add doesn't add anything (so also not the name) if the value is falsy.
  • edited June 26, 2020
    This doesn't seem to compile correctly? I'm getting an orange box in the postscript and output is not giving me anything

    I see what you're saying though, and I think this should work, editting my spaghetti from before:

    It isn't case insensitive.. but at this point, I only had to edit 1 URI in my zotero.


    if (Translator.BetterTeX && item.attachments) {
    for (const name of ['pdfsiterussian', 'pdfsiteenglish']) {
    if (name === 'pdfsiterussian'){
    reference.add({
    name: name,
    value: item.attachments
    .filter(att => att.url && (name === 'pdfsiterussian' ? att.title.includes('russian') && att.title.includes('site') : !att.title.includes('russian')))
    .map(att => att.url)
    .join('; '),
    enc: 'verbatim'
    })
    } else{
    reference.add({
    name: name,
    value: item.attachments
    .filter(att => att.url && (name === 'pdfsiteenglish' ? att.title.includes('english') && att.title.includes('site') : !att.title.includes('english')))
    .map(att => att.url)
    .join('; '),
    enc: 'verbatim'
    })
    }
    }
    }
  • edited June 26, 2020
    Sorry, should have been

    if (Translator.BetterTeX && item.attachments) {
    for (const lang of ['russian', 'english']) {
    reference.add({
    name: `pdfsite${lang}`,
    value: item.attachments.filter(att=> att.url && att.title.includes('site') && att.title.includes(lang)).map(att => att.url)[0],
    enc: 'verbatim',
    })
    }
    }


    Your code will do the job, but the loop doesn't really make sense there. A simplified version would be

    if (Translator.BetterTeX && item.attachments) {
    reference.add({
    name: 'pdfsiterussian',
    value: item.attachments
    .filter(att => att.url && att.title.includes('russian') && att.title.includes('site'))
    .map(att => att.url)
    .join('; '),
    enc: 'verbatim'
    })

    reference.add({
    name: 'pdfsiteenglish',
    value: item.attachments
    .filter(att => att.url && att.title.includes('english') && att.title.includes('site'))
    .map(att => att.url)
    .join('; '),
    enc: 'verbatim'
    })
    }


    but note that your version gathers all russian/english URLs, and you previously said you only wanted the first.
Sign In or Register to comment.