<div dir="ltr">DM,<div><br></div><div>Thanks for that thorough explanation. I was trying to figure out if I was simply missing a call like book.getBooks() or book.getRootKeys() or similar or if I needed to construct it more deeply.<br>
<div class="gmail_extra"><br><br><div class="gmail_quote">On Sat, Jan 11, 2014 at 7:21 AM, DM Smith <span dir="ltr">&lt;<a href="mailto:dmsmith@crosswire.org" target="_blank">dmsmith@crosswire.org</a>&gt;</span> wrote:<br>
<blockquote class="gmail_quote" style="margin:0 0 0 .8ex;border-left:1px #ccc solid;padding-left:1ex"><div class="im"><br>
On Jan 11, 2014, at 1:15 AM, Greg Hellings &lt;<a href="mailto:greg.hellings@gmail.com">greg.hellings@gmail.com</a>&gt; wrote:<br>
<br>
&gt; I&#39;m trying to decipher the API so I can fetch a list of the top-level keys in a module. e.g. for a Bible a list of all the Bible books that are valid for a given Book or such. What is the preferred way?<br>
<br>
</div>It depends. Typically on use case.<br>
<br>
Are you asking specifically about Bibles or modules in general?<br></blockquote><div><br></div><div>I was asking in general.</div><div> </div><blockquote class="gmail_quote" style="margin:0 0 0 .8ex;border-left:1px #ccc solid;padding-left:1ex">

<br>
Not sure what top-level means to you. It probably differs between different module types. For a dictionary, do you mean all the terms that don&#39;t link to others? For a Gen Book do you mean all the first nodes in the tree? For a Bible do you mean all the books of the Bible? What about Bible introductions (e.g. module and testament level)?<br>
</blockquote><div><br></div><div>For a Bible I was meaning all the books in the particular module/Book that contain content. For Gen Book I was meaning all the top-level sections.</div><div> </div><blockquote class="gmail_quote" style="margin:0 0 0 .8ex;border-left:1px #ccc solid;padding-left:1ex">

<br>
And I&#39;m not sure what you mean by valid. There are several levels of valid?<br>
<br>
Given a key is it allowable for the module.<br>
Is Genesis allowable for a Bible? How about 1 Hesitations?<br>
Is Fred allowable for a dictionary? How about xyz?<br>
Is Fred allowable for a Daily Devotion? How about March 3?<br>
<br>
Does the key have content in the module?<br>
Is Gen 1:1 in the Bible? Is Genesis in the Bible?<br>
Is xyz in the Dictionary?<br>
Is March 3 in the Daily Devotion?<br>
<br>
Is the key defined for the versification?<br>
Is Bel and the Dragon defined for the KJV v11n?<br>
<br>
Answering for Bibles:<br>
A Bible module (in JSword, we call a module a Book and a Bible module is an AbstractPassageBook) always has a Versification. A Key can only be understood in the context of a Bible&#39;s Versification.<br>
Given a Bible Book (aka module), b, you ask it for the Versification:<br>
b.getVersification();<br>
The Versification object has all kinds of methods to query what&#39;s allowable. Internally, it has a BibleBookList, which is an ordered list of BibleBook. This can be queried in a variety of ways:<br>
<br>
There are two kinds of BibleBook existence questions for a Versification:<br>
1) Given a String, can it be understood as a BibleBook, using getBook(s) or isBook(s). E.g. Ge for Genesis.<br>
2) Is a BibleBook in the Versification using containsBook(bb)<br>
<br>
There are 3 different ways to iterate over the list:<br>
1) Iterate using getBookIterator<br>
2) Numerically using getBookCount() and getBook(n)<br>
3) Adjacency using getFirstBook(), getLastBook(), getNextBook(bb), getPreviousBook(bb)<br>
<br>
<br>
If you are wanting to know whether a particular Bible has a BibleBook, you might be asking whether there is any content for the BibleBook in the module. This can either be determined exactly (is there at least one key in the BibleBook that would return content) or heuristically (Is chapter 1, verse 1 have content for the BibleBook). The decision is one of performance.<br>

<br>
Aside, the SWORD module building programs append verse content to the dat file in the order it occurs in the source file. Then they write the start and length to the idx file for that verse. If the verses are in the canonical, versification order then the question can be answered with great performance as a Bible book will have a start and a length in the dat file. If the source is not in canonical, versification order or if the append mode of the module builder is used then this is not true. So, JSword cannot make assumptions about the order of verses in the dat files.<br>

<br>
To do the heuristic check:<br>
Build the key for the first chapter and verse of the book, using a verse constructor v = new Verse(v11n, bb, 1, 1).<br>
Then check for existence with b.contains(v)<br>
<br>
To do the full check, it really depends upon whether you are wanting to check just one BibleBook or every BibleBook. Assuming the latter case, which needs to check every last verse in the module for existence:<br>
b.getGlobalKeyList() will return the list of all keys that are actually in the Book. Chris B has optimized this to be very fast.<br>
Then create a VerseRange for each BibleBook and test to see if that verse range intersects with the global key list.<br>
To create a VerseRange you supply the first and last verse of the range:<br>
new VerseRange(v11n, new Verse(v11n, bb, 0, 0), new Verse(v11n, bb, v11n.getLastChapter(bb), v11n.getLastVerse(bb, v11n.getLastChapter())<br>
(Note use 1, 1 if you are not interested in the Book Intro or the first chapter intro. The range will include other chapter&#39;s intros.)<br>
Then test the global key list to see if it contains any of the keys in the VerseRange. (Note, the contains method on a global key list tests contains all).<br>
JSword does not have a &quot;contain any&quot;, which is needed here. (BTW, we can add such if needed)<br>
It&#39;d be something like:<br>
for each verse in the verse range<br>
  if is in the global key list<br>
    then return true as we are done<br>
end for<br>
return false<br></blockquote><div><br></div><div>What I ended up doing, though I wasn&#39;t sure this would be the best way from just glancing at the API, though it appears to be, is taking the list from getGlobalKeyList(), splitting on the &#39;.&#39; character, and creating a Set out of that. Then using those results to output. It does result in my ordering being according to the module rather than the versification, but that is sufficient for my purposes. But I&#39;m running into a problem with Gen Books with my final output algorithm. I&#39;m using code like this to output the requested sub-section of a module:</div>
<div><br></div><div>for (Key key : book.getKey(requestedReference)) {</div><div>    BookData data = new BookData(book, key);</div><div>    </div><div>    System.out.println(OSISUtil.getCanonicalText(data.getOSISFragment()));</div>
<div>}</div><div><br></div><div>This works fine for Bibles. I can iterate a single chapter, verse range, book, etc in a Bible. I can get out any entry in a Dictionary. I can even get the contents of a Gen Book if that sub-tree is only one level deep. E.g. I can get out Pilgrim&#39;s Progress &#39;SOURCE&#39; section or &#39;TITLE&#39; section. But I can&#39;t get out &#39;THE_AUTHOR&#39;S_APOLOGY_FOR_HIS_BOOK&#39; or &#39;PART_I&#39;. Both of them throw a NoSuchKeyException, although getGlobalKeyList() returned a key whose OSIS ID claims to be equal to that string. Am I doing something wrong here, or breaking some sort of assumption about module types?</div>
<div><br></div><div> </div><blockquote class="gmail_quote" style="margin:0 0 0 .8ex;border-left:1px #ccc solid;padding-left:1ex">
<br>
In Bible Desktop, we want something like this to help build the Book, chapter, verse navigator based on content of the Bible rather than on its Versification. E.g. No sense showing OT book names when the OT is not part of the module. Or showing all the Books when the module only contains John.<br>

<br></blockquote><div><br></div><div>Exactly, I&#39;m trying to generate a list like this for any type of module that is passed in.</div><div><br></div><div>--Greg</div><div> </div><blockquote class="gmail_quote" style="margin:0 0 0 .8ex;border-left:1px #ccc solid;padding-left:1ex">

It may be that Chris B has implemented something like this for STEP.<br>
<br>
If this doesn&#39;t answer your question or point you in a useful direction, please ask.<br>
<br>
In Him,<br>
        DM<br>
<br>
<br>_______________________________________________<br>
jsword-devel mailing list<br>
<a href="mailto:jsword-devel@crosswire.org">jsword-devel@crosswire.org</a><br>
<a href="http://www.crosswire.org/mailman/listinfo/jsword-devel" target="_blank">http://www.crosswire.org/mailman/listinfo/jsword-devel</a><br>
<br></blockquote></div><br></div></div></div>