Libreoffice/openoffice linking citations to references

I have written the following macros for libreoffice odt files to link citations to a bookmark for the references. The bookmark (called References) has to be currently set manually.


Sub linkReferencesNumbered
refSearch("([0-9]|[1-9][0-9]|[1-9][0-9][0-9])")
End Sub


Sub linkReferencesAuthorDate
refSearch("\p{Lu}[\p{Lu}\p{Ll}'-]*( et al.) [0-9]{4}")
refSearch("\p{Lu}[\p{Lu}\p{Ll}'-]* [0-9]{4}")
refSearch("\p{Lu}[\p{Lu}\p{Ll}'-]* and \p{Lu}[\p{Lu}\p{Ll}'-]* [0-9]{4}")
End Sub

Sub refSearch(sSearchString)
oDoc = ThisComponent
oCursor = oDoc.Text.createTextCursor

oSearch = oDoc.createSearchDescriptor
oSearch.SearchRegularExpression = True
oSearch.SearchString = sSearchString
oFound = oDoc.findFirst(oSearch)

While Not IsNull(oFound)
oCursor = oFound.Text.createTextCursorByRange(oFound)
if isObject(oCursor.Start.ReferenceMark) Then oCursor.HyperLinkURL = "#References"
oFound = oDoc.findNext(oFound, oSearch)
Wend

End Sub
  • sorry. The first macro should be:

    Sub linkReferencesNumbered
    refSearch("([1-9][0-9][0-9]|[1-9][0-9]|[0-9])")
    End Sub
  • II have extensively modified the macro to link (in most cases) directly to the cited reference in the bibliography list. The macros should work for both numbered and author date citations. However, there are some styles were they do not work (i.e., styles that put lines in between the references).

    Sub linkNumberedReferences
    insertZoteroBookmarks(TRUE)
    refSearchnumbered("([1-9][0-9][0-9]|[1-9][0-9]|[0-9])")
    End Sub

    Sub refSearchnumbered(sSearchString)
    oDoc = ThisComponent
    oCursor = oDoc.Text.createTextCursor
    oSearch = oDoc.createSearchDescriptor
    oSearch.SearchRegularExpression = True
    oSearch.SearchString = sSearchString
    oFound = oDoc.findFirst(oSearch)
    While Not IsNull(oFound)
    oCursor = oFound.Text.createTextCursorByRange(oFound)
    if isObject(oCursor.Start.ReferenceMark) Then
    bm = "#_Ref_" & oCursor.String
    oCursor.HyperLinkURL = bm
    End If
    oFound = oDoc.findNext(oFound, oSearch)
    Wend
    End Sub

    Sub linkAuthorDateReferences
    insertZoteroBookmarks(FALSE)
    refSearch("\p{Lu}[\p{Lu}\p{Ll}'-]*( et al.)(,?) [0-9]{4}")
    refSearch("(\p{Lu}[\p{Lu}\p{Ll}'-]* and )?(\p{Lu}[\p{Lu}\p{Ll}'-]*)(,?) [0-9]{4}")
    refSearch("(\p{Lu}[\p{Lu}\p{Ll}'-]*, \p{Lu}[\p{Lu}\p{Ll}'-]*, and \p{Lu}[\p{Lu}\p{Ll}'-]*)(,?) [0-9]{4}")
    End Sub

    Sub refSearch(sSearchString)
    oDoc = ThisComponent
    oCursor = oDoc.Text.createTextCursor
    oSearch = oDoc.createSearchDescriptor
    oSearch.SearchRegularExpression = True
    oSearch.SearchString = sSearchString
    oFound = oDoc.findFirst(oSearch)
    While Not IsNull(oFound)
    oCursor = oFound.Text.createTextCursorByRange(oFound)
    if isObject(oCursor.Start.ReferenceMark) Then
    bm = "#_Ref_" & findFirstWord (oCursor.string)
    oCursor.HyperLinkURL = bm
    End If
    oFound = oDoc.findNext(oFound, oSearch)
    Wend
    End Sub

    Function findFirstWord (oString)
    oReturnString = Split (oString, " ")
    findFirstWord = Replace (oReturnString(0), ",", "")
    End Function

    Function Replace(Source As String, Search As String, NewPart As String)
    Dim Result As String
    Result = join(split(Source, Search), NewPart)
    Replace = Trim(Result)
    End Function

    Sub insertZoteroBookmarks(bNumbered As boolean)
    deleteRefBookmarks
    Dim vSections
    Dim sEventNames 'Array of event types
    Dim sNames
    oDoc = ThisComponent
    oCursor = oDoc.Text.createTextCursor
    vSections = ThisComponent.TextSections()
    sEventNames = vSections.getElementNames()
    For Each sEventName In sEventNames
    If instr (sEventName, "ZOTERO") Then
    oSection = oDoc.getTextSections().getByName(sEventName)
    oSectionAnchor = oSection.getAnchor
    oViewCursor = oDoc.CurrentController.getViewCursor()
    oViewCursor.gotoRange(oSectionAnchor, false)
    oSelection = oDoc.getCurrentSelection (oViewCursor)
    oSel = oSelection.getbyIndex(0)
    iCount=0
    oPE= oSel.createEnumeration()
    Do While oPE.hasMoreElements()
    oPar = oPE.nextElement()
    If oPar.supportsService("com.sun.star.text.Paragraph") Then
    oSecEnum = oPar.createEnumeration()
    Do While oSecEnum.hasMoreElements()
    oParSection = oSecEnum.nextElement()
    If oParSection.TextPortionType = "Text" Then
    bm = ThisComponent.createInstance("com.sun.star.text.Bookmark")
    oCurs = oParSection.getText().createTextCursorByRange(oParSection)
    If bNumbered Then
    iCount = iCount +1
    bm.Name = "_Ref_" & iCount
    Else
    bm.Name = "_Ref_" & findFirstWord (oCurs.string)
    End if
    oDoc.Text.insertTextContent(oCurs, bm, True)
    End If
    Loop
    End If
    Loop
    End If
    Next
    End Sub


    Sub deleteRefBookmarks
    Dim i As Integer, oBookmarks, sBookMarkNames()
    If HasUnoInterfaces( ThisComponent, "com.sun.star.text.XBookmarksSupplier" ) Then
    oBookmarks = ThisComponent.getBookmarks()
    sBookMarkNames = oBookmarks.getElementNames()
    For i = 0 To Ubound( sBookMarkNames )
    If instr(sBookMarkNames(i), "_Ref_") Then
    oBookmarks.getByName( sBookMarkNames( i ) ).dispose()
    End if
    Next
    End If
    End Sub
  • After some comments from a colleague, I have corrected a couple of things (use Sub linkNumberedReferences for numbered references such as Vancover, and Sub linkAuthorDateReferences for author date such as Harvard - adding an additional search for say just author should be easy :

    Sub linkNumberedReferences
    insertZoteroBookmarks(TRUE)
    refSearchnumbered("([1-9][0-9][0-9]|[1-9][0-9]|[0-9])")
    End Sub

    Sub refSearchnumbered(sSearchString)
    oDoc = ThisComponent
    oSearch = oDoc.createSearchDescriptor
    oSearch.SearchRegularExpression = True
    oSearch.SearchString = sSearchString
    oFound = oDoc.findFirst(oSearch)
    While Not IsNull(oFound)
    oCursor = oFound.Text.createTextCursorByRange(oFound)
    if isObject(oCursor.Start.ReferenceMark) Then
    bm = "#_Ref_" & oCursor.String
    oCursor.HyperLinkURL = bm
    End If
    oFound = oDoc.findNext(oFound, oSearch)
    Wend
    End Sub

    Sub linkAuthorDateReferences
    insertZoteroBookmarks(FALSE)
    refSearch("\p{Lu}[\p{Lu}\p{Ll}'-]*( et al.)(,?) [0-9]{4}")
    refSearch("(\p{Lu}[\p{Lu}\p{Ll}'-]* and )?(\p{Lu}[\p{Lu}\p{Ll}'-]*)(,?) [0-9]{4}")
    refSearch("(\p{Lu}[\p{Lu}\p{Ll}'-]*, \p{Lu}[\p{Lu}\p{Ll}'-]*, and \p{Lu}[\p{Lu}\p{Ll}'-]*)(,?) [0-9]{4}")
    End Sub

    Sub refSearch(sSearchString)
    oDoc = ThisComponent
    oSearch = oDoc.createSearchDescriptor
    oSearch.SearchRegularExpression = True
    oSearch.SearchString = sSearchString
    oFound = oDoc.findFirst(oSearch)
    While Not IsNull(oFound)
    oCursor = oFound.Text.createTextCursorByRange(oFound)
    if isObject(oCursor.Start.ReferenceMark) Then
    bm = "#_Ref_" & findFirstWord (oCursor.string)
    oCursor.HyperLinkURL = bm
    End If
    oFound = oDoc.findNext(oFound, oSearch)
    Wend
    End Sub

    Function findFirstWord (oString)
    oReturnString = Split (oString, " ")
    findFirstWord = Replace (Replace (oReturnString(0), ",", ""), Chr(10), "")
    End Function

    Function Replace(Source As String, Search As String, NewPart As String)
    Dim Result As String
    Result = join(split(Source, Search), NewPart)
    Replace = Trim(Result)
    End Function

    Sub insertZoteroBookmarks(bNumbered As boolean)
    deleteRefBookmarks
    Dim vSections
    Dim sEventNames 'Array of event types
    Dim sNames
    oDoc = ThisComponent
    vSections = ThisComponent.TextSections()
    sEventNames = vSections.getElementNames()
    For Each sEventName In sEventNames
    If instr (sEventName, "ZOTERO") Then Exit For
    Next
    oSection = oDoc.getTextSections().getByName(sEventName)
    oSectionAnchor = oSection.getAnchor
    oCursor = oSectionAnchor.getText().createTextCursorByRange(oSectionAnchor)
    oPE = oCursor.createEnumeration()
    iCount = 0
    Do While oPE.hasMoreElements()
    oPar = oPE.nextElement()
    If oPar.supportsService("com.sun.star.text.Paragraph") Then
    iCount = iCount +1
    bm = ThisComponent.createInstance("com.sun.star.text.Bookmark")
    oCurs = oPar.getText().createTextCursorByRange(oPar)
    If bNumbered Then
    bm.Name = "_Ref_" & iCount
    Else
    bm.Name = "_Ref_" & findFirstWord (oCurs.string)
    End if
    If Not oDoc.getBookmarks().hasByName(bm.Name) Then oDoc.Text.insertTextContent(oCurs, bm, True)
    End If
    Loop
    End sub

    Sub deleteRefBookmarks
    Dim i As Integer, oBookmarks, sBookMarkNames()
    If HasUnoInterfaces( ThisComponent, "com.sun.star.text.XBookmarksSupplier" ) Then
    oBookmarks = ThisComponent.getBookmarks()
    sBookMarkNames = oBookmarks.getElementNames()
    For i = 0 To Ubound( sBookMarkNames )
    If instr(sBookMarkNames(i), "_Ref_") Then
    oBookmarks.getByName( sBookMarkNames( i ) ).dispose()
    End if
    Next
    End If
    End Sub
  • edited 9 days ago
    Hi,

    as I am not familiar with LO Basic nor with Macros at all, it took me some time to get the things working. Let me drop here some comments for potential other „noobs“:

    -citations in the document have to be as ReferenceMarks (option under „Set Document Preferences“ button: „ReferenceMarks“/„Bookmarks“)

    -Out of all the „routines“/„Subs“ that appear in the list of macros, run only one: „linkNumberedReferences“ or „linkAuthorDateReferences“, based on the actual citation style used in Your document (other „Subs“ are helping functions for organizing the source code)

    -After Macro is run, the numbers marking the references in text (e.g. [27]) should get underlined to symbolise that they became hyperlinks. But I observed also that nothing visible happened which is some bug of my LO distribution (6.2.8.2. x64). Try to export PDF to see, whether the references in text changed into clickable hyperlinks

    -The references does not become clickable hyperlinks in your ODT, it works only in exported PDF (when you hover your mouse over the reference in our ODT, you still can see the „ZOTERO“ system ToolTipText)

    -You don't do the Unlink Citations as it would break also the result of the Macro

    Finally, many thanks to the author of this macro!
Sign In or Register to comment.