Take a list of some kind of object, a conversion function, an id and a
    title Return XML representing an ATOM feed

def makeObjectFeed(
        paginator, objectToXMLFunction, feedId, title, webRoot,
        idAttr="id", nameAttr="name", dateAttr=None, request=None, page=1,
        count=20, author=APP_AUTHOR):
    """
    Take a list of some kind of object, a conversion function, an id and a
    title Return XML representing an ATOM feed
    """

    listSize = paginator.count
    if listSize:
        object_list = paginator.page(page).object_list
    else:
        object_list = []
    count = int(count)
    originalId = feedId
    idParts = feedId.split("?", 1)
    if len(idParts) == 2:
        feedId = idParts[0]
    if request:
        GETStruct = request.GET
    else:
        GETStruct = False
    feedTag = etree.Element(ATOM + "feed", nsmap=ATOM_NSMAP)
    # The id tag is very similar to the 'self' link
    idTag = etree.SubElement(feedTag, ATOM + "id")
    idTag.text = "%s/%s" % (webRoot, feedId)
    # The title is passed in from the calling function
    titleTag = etree.SubElement(feedTag, ATOM + "title")
    titleTag.text = title
    # The author is passed in from the calling function and required to be valid ATOM
    if author:
        authorTag = etree.SubElement(feedTag, ATOM + "author")
        nameTag = etree.SubElement(authorTag, ATOM + "name")
        urlTag = etree.SubElement(authorTag, ATOM + "uri")
        nameTag.text = author.get('name', 'UNT')
        urlTag.text = author.get('uri', 'http://library.unt.edu/')
    # The updated tag is a
    updatedTag = etree.SubElement(feedTag, ATOM + "updated")
    updatedTag.text = xsDateTime_format(localize_datetime(datetime.now()))
    # We will always show the link to the current 'self' page
    linkTag = etree.SubElement(feedTag, ATOM + "link")
    linkTag.set("rel", "self")
    if not request or not request.META['QUERY_STRING']:
        linkTag.set("href", "%s/%s" % (webRoot, feedId))
    else:
        linkTag.set(
            "href", "%s/%s?%s" % (
                webRoot, feedId, urllib.urlencode(request.GET, doseq=True)
            )
        )
    # We always have a last page
    endLink = etree.SubElement(feedTag, ATOM + "link")
    endLink.set("rel", "last")
    if GETStruct:
        endLinkGS = GETStruct.copy()
    else:
        endLinkGS = {}
    endLinkGS.update({"page": paginator.num_pages})
    endLink.set(
        "href", "%s/%s?%s" % (
            webRoot, feedId, urllib.urlencode(endLinkGS, doseq=True)
        )
    )
    # We always have a first page
    startLink = etree.SubElement(feedTag, ATOM + "link")
    startLink.set("rel", "first")
    if GETStruct:
        startLinkGS = GETStruct.copy()
    else:
        startLinkGS = {}
    startLinkGS.update({"page": paginator.page_range[0]})
    startLink.set(
        "href", "%s/%s?%s" % (
            webRoot, feedId, urllib.urlencode(startLinkGS, doseq=True)
        )
    )
    # Potentially there is a previous page, list it's details
    if paginator.page(page).has_previous():
        prevLink = etree.SubElement(feedTag, ATOM + "link")
        prevLink.set("rel", "previous")
        if GETStruct:
            prevLinkGS = GETStruct.copy()
        else:
            prevLinkGS = {}
        prevLinkGS.update(
            {"page": paginator.page(page).previous_page_number()}
        )
        prevLinkText = "%s/%s?%s" % (
            webRoot, feedId, urllib.urlencode(prevLinkGS, doseq=True)
        )
        prevLink.set("href", prevLinkText)
    # Potentially there is a next page, fill in it's details
    if paginator.page(page).has_next():
        nextLink = etree.SubElement(feedTag, ATOM + "link")
        nextLink.set("rel", "next")
        if GETStruct:
            nextLinkGS = GETStruct.copy()
        else:
            nextLinkGS = {}
        nextLinkGS.update({"page": paginator.page(page).next_page_number()})
        nextLinkText = "%s/%s?%s" % (
            webRoot, feedId, urllib.urlencode(nextLinkGS, doseq=True)
        )
        nextLink.set("href", nextLinkText)
    for o in object_list:
        objectXML = objectToXMLFunction(o)
        if dateAttr:
            dateStamp = getattr(o, dateAttr)
        else:
            dateStamp = None
        althref = feedId.strip('/').split('/')[-1]
        althref = '%s/%s/%s/' % (
            webRoot, althref, getattr(o, idAttr)
        )
        objectEntry = wrapAtom(
            xml=objectXML,
            id='%s/%s%s/' % (webRoot, originalId, getattr(o, idAttr)),
            title=getattr(o, nameAttr),
            updated=dateStamp,
            alt=althref
        )
        feedTag.append(objectEntry)
    return feedTag