net.bible.service.format.osistohtml.ReferenceHandler.java Source code

Java tutorial

Introduction

Here is the source code for net.bible.service.format.osistohtml.ReferenceHandler.java

Source

package net.bible.service.format.osistohtml;

import java.util.Iterator;

import net.bible.service.common.Constants;
import net.bible.service.common.Logger;

import org.apache.commons.lang.StringUtils;
import org.crosswire.jsword.book.OSISUtil;
import org.crosswire.jsword.passage.Key;
import org.crosswire.jsword.passage.Passage;
import org.crosswire.jsword.passage.PassageKeyFactory;
import org.crosswire.jsword.passage.RestrictionType;
import org.crosswire.jsword.passage.VerseRange;
import org.xml.sax.Attributes;

/**
 * Convert OSIS tags into html tags
 * 
 *  Example OSIS tags from KJV Ps 119 v1 showing title, w, note
<title canonical="true" subType="x-preverse" type="section">
   <foreign n="?">ALEPH.</foreign>
</title>
<w lemma="strong:H0835">Blessed</w> <transChange type="added">are</transChange> <w lemma="strong:H08549">the undefiled</w>
...  <w lemma="strong:H01980" morph="strongMorph:TH8802">who walk</w> 
... <w lemma="strong:H03068">of the <seg><divineName>Lord</divineName></seg></w>.
<note type="study">undefiled: or, perfect, or, sincere</note>
    
Example of notes cross references from ESV 
In the <note n="a" osisID="Gen.1.1!crossReference.a" osisRef="Gen.1.1" type="crossReference"><reference osisRef="Job.38.4-Job.38.7">Job 38:4-7</reference>; <reference osisRef="Ps.33.6">Ps. 33:6</reference>; <reference osisRef="Ps.136.5">136:5</reference>; <reference osisRef="Isa.42.5">Isa. 42:5</reference>; <reference osisRef="Isa.45.18">45:18</reference>; <reference osisRef="John.1.1-John.1.3">John 1:1-3</reference>; <reference osisRef="Acts.14.15">Acts 14:15</reference>; <reference osisRef="Acts.17.24">17:24</reference>; <reference osisRef="Col.1.16-Col.1.17">Col. 1:16, 17</reference>; <reference osisRef="Heb.1.10">Heb. 1:10</reference>; <reference osisRef="Heb.11.3">11:3</reference>; <reference osisRef="Rev.4.11">Rev. 4:11</reference></note>beginning
 * 
 * @author Martin Denham [mjdenham at gmail dot com]
 * @see gnu.lgpl.License for license details.<br>
 *      The copyright to this program is held by it's author.
 */
public class ReferenceHandler {

    private OsisToHtmlParameters parameters;

    private String currentRefOsisRef;

    private NoteHandler noteHandler;

    private HtmlTextWriter writer;

    private static final Logger log = new Logger("ReferenceHandler");

    public ReferenceHandler(OsisToHtmlParameters osisToHtmlParameters, NoteHandler noteHandler,
            HtmlTextWriter theWriter) {
        this.parameters = osisToHtmlParameters;
        this.noteHandler = noteHandler;
        this.writer = theWriter;
    }

    public void start(Attributes attrs) {
        // store the osisRef attribute for use with the note
        String target = attrs.getValue(OSISUtil.OSIS_ATTR_REF);
        start(target);
    }

    protected void start(String target) {
        // don't need to do anything until closing reference tag except..
        // delete separators like ';' that sometimes occur between reference tags
        writer.clearTempStore();
        writer.writeToTempStore();
        // store the osisRef attribute for use with the note
        this.currentRefOsisRef = target;
    }

    public void end() {
        writer.finishWritingToTempStore();

        if (noteHandler.isInNote() || parameters.isAutoWrapUnwrappedRefsInNote()) {
            noteHandler.addNoteForReference(writer.getTempStoreString(), currentRefOsisRef);
        } else {
            String refText = writer.getTempStoreString();
            writer.write(getReferenceTag(currentRefOsisRef, refText));
        }

        // and clear the buffer
        writer.clearTempStore();
        currentRefOsisRef = null;
    }

    /** create a link tag from an OSISref and the content of the tag
     */
    private String getReferenceTag(String reference, String content) {
        log.debug("Ref:" + reference + " Content:" + content);
        StringBuilder result = new StringBuilder();
        try {

            //JSword does not know the basis (default book) so prepend it if it looks like JSword failed to work it out
            //We only need to worry about the first ref because JSword uses the first ref as the basis for the subsequent refs
            // if content starts with a number and is not followed directly by an alpha char e.g. 1Sa
            if (reference == null && content != null && content.length() > 0
                    && StringUtils.isNumeric(content.subSequence(0, 1))
                    && (content.length() < 2 || !StringUtils.isAlphaSpace(content.subSequence(1, 2)))) {

                // maybe should use VerseRangeFactory.fromstring(orig, basis)
                // this check for a colon to see if the first ref is verse:chap is not perfect but it will do until JSword adds a fix
                int firstColonPos = content.indexOf(":");
                boolean isVerseAndChapter = firstColonPos > 0 && firstColonPos < 4;
                if (isVerseAndChapter) {
                    reference = parameters.getBasisRef().getBook().getOSIS() + " " + content;
                } else {
                    reference = parameters.getBasisRef().getBook().getOSIS() + " "
                            + parameters.getBasisRef().getChapter() + ":" + content;
                }
                log.debug("Patched reference:" + reference);
            } else if (reference == null) {
                reference = content;
            }

            // convert urns of type book:key to sword://book/key to simplify urn parsing (1 fewer case to check for).  
            // Avoid urls of type 'matt 3:14' by excludng urns with a space
            if (reference.contains(":") && !reference.contains(" ") && !reference.startsWith("sword://")) {
                reference = "sword://" + reference.replace(":", "/");
            }

            boolean isFullSwordUrn = reference.contains("/") && reference.contains(":");
            if (isFullSwordUrn) {
                // e.g. sword://StrongsRealGreek/01909
                // don't play with the reference - just assume it is correct
                result.append("<a href='").append(reference).append("'>");
                result.append(content);
                result.append("</a>");
            } else {
                Passage ref = (Passage) PassageKeyFactory.instance().getKey(parameters.getDocumentVersification(),
                        reference);
                boolean isSingleVerse = ref.countVerses() == 1;
                boolean isSimpleContent = content.length() < 3 && content.length() > 0;
                Iterator<VerseRange> it = ref.rangeIterator(RestrictionType.CHAPTER);

                if (isSingleVerse && isSimpleContent) {
                    // simple verse no e.g. 1 or 2 preceding the actual verse in TSK
                    result.append("<a href='").append(Constants.BIBLE_PROTOCOL).append(":")
                            .append(it.next().getOsisRef()).append("'>");
                    result.append(content);
                    result.append("</a>");
                } else {
                    // multiple complex references
                    boolean isFirst = true;
                    while (it.hasNext()) {
                        Key key = it.next();
                        if (!isFirst) {
                            result.append(" ");
                        }
                        result.append("<a href='").append(Constants.BIBLE_PROTOCOL).append(":")
                                .append(key.iterator().next().getOsisRef()).append("'>");
                        result.append(key);
                        result.append("</a>");
                        isFirst = false;
                    }
                }
            }
        } catch (Exception e) {
            log.error("Error parsing OSIS reference:" + reference);
            // just return the content with no html markup
            result.append(content);
        }
        return result.toString();
    }
}