XML Output

Below is actual XML output from the PHP of the previous post. XML is way cool. The XML shown can be generated directly from your browser with the following URL:

http://theholyscriptures.info/PHP/ZLookup_XML.php?vol=1&book=1&chapter=1&verse=1-3

<scriptures type="List" title="The Holy Scriptures" sql="">
  <volume num="1" title="Old Testament">
    <book num="1" title="Genesis" longtitle="The First Book of Moses called Genesis" chapters="50">
      <chapter num="1" title="Chapter 1 - God creates the Earth" comments="1">
        <verse id="1" num="1" mark="" score="">
          IN the beginning God created the heaven and the earth.
          <comment type="World" name="There is a God"/>
        </verse>
        <verse id="2" num="2" mark="" score="">
          And the earth was without form, and void; and darkness was upon the face of the deep.  And the Spirit of God moved upon the face of the waters.
        </verse>
        <verse id="3" num="3" mark="" score="">
          And God said, Let there be light: and there was light.
        </verse>
      </chapter>
    </book>
  </volume>
</scriptures>

PHP Usage

Sometimes, for a carpenter, every solution involves a hammer. PHP is like that. It’s every web developers hammer. My problem is that many PHP based apps, because of the way they are written, are hard to understand and maintain. Also since PHP apps runs on the server side, they are always going to be slower than running JavaScript on the client side. Finally, a PHP app doesn’t fit the AJAX paradigm that I think is the future of the web.

Therefore my PHP usage is primarily as a data bridge to bring the other pieces (JavaScript, xhtml, MySQL) together. Therefore TheHolyScriptures.info has no need for PHP frameworks because it’s just not that complicated. I want all my PHP to be straightforward, fast, short, simple to maintain. Every time I call the server (via AJAX) I execute PHP to fetch and format the data – and never for web page manipulation. TheHolyScriptures.info requires PHP 5.2 or greater for built in XML support. Here’s a short example of a PHP script I use and how it builds the XML (parts are obfuscated for security reasons…).:

$MyPswd = "real password goes here...";
$DB_Connection = mysql_connect("localhost", "mackle_lds", $MyPswd) or die ('Cannot connect to database: '.mysql_error());
mysql_select_db("mackle_LDS");

 // prevent SQL injection attacks with mysql_real_escape_string
$volume_id = mysql_real_escape_string($_GET["volume"]);
$book_id = mysql_real_escape_string($_GET["book"]);
$chapter = mysql_real_escape_string($_GET["chapter"]);

// Tell the browser the output is XML Unicode
header("Content-Type: text/xml; charset=utf-8");

// Query for volume and book
$sql  = "SELECT volume_title, num_chapters, book_title, book_title_long FROM scriptures_books WHERE ";
$sql .= "volume_id = $volume_id And book_id = $book_id";
$result = mysql_query($sql,$DB_Connection);

if ($row = mysql_fetch_object($result)) {
  
  //Create XML document using the DOM 
  $xmlDoc = new DomDocument('1.0', 'UTF-8');
  
  $scriptures->setAttribute('type','Fill');
  $scriptures->setAttribute('title','The Holy Scriptures');
  if ($SQL == 'Y') {$scriptures->setAttribute('sql',$sql2);} // Used for diagnostics in admin mode
  
  // Create volume sub-node                 
  $volume = $scriptures->appendChild($xmlDoc->createElement('volume')); 
  $volume->setAttribute('num','1');
  $volume->setAttribute('title',$row->volume_title);
  
  // Create book sub-node
  $book = $volume->appendChild($xmlDoc->createElement('book'));        
  $book->setAttribute('num','1');
  $book->setAttribute('title',$row->book_title);
  
  // Query for chapter and verses
  $sql2 = "SELECT chapter, chapter_name, verse_id, verse, verse_scripture, html_top, html_right, html_bottom,";
  $sql2 .= " html_left, html_replace, groupname FROM lds_scriptures_verses ";
  $sql2 .= " WHERE volume_id = $volume_id And book_id = $book_id And chapter = $chapter";
  $result2 = mysql_query($sql2,$DB_Connection);
  $FirstTime = true;
  while ($row2 = mysql_fetch_object($result2)) {
     if ($FirstTime === true) {
       // Create the chapter sub-node. We are only doing one chapter of verses.
       $chapter = $book->appendChild($xmlDoc->createElement('chapter'));
       $chapter->setAttribute('num',$row2->chapter);
       $chapter->setAttribute('title',$row2->chapter_name);
       $chapter->setAttribute('comments','');
       $FirstTime = false;
    }
    if ($row2->html_replace === '') {
      // Format the standard version with formatting as defined, if any
      $verse_text = str_replace('\r\n','<br>',$row2->verse_scripture);
      $verse_text = $row2->html_top.$row2->html_left.$verse_text.$row2->html_right.$row2->html_bottom;
    } else {
      // Assign the special formatted verse,  rather than the raw text verse used for searching.
      $verse_text = $row2->html_replace;
    }
    // Create the chapter verse sub-node and attributes
    $verse = $chapter->appendChild($xmlDoc->createElement('verse'));
    $verse->appendChild($xmlDoc->createTextNode($verse_text));
    $verse->setAttribute('id',$row2->verse_id);
    $verse->setAttribute('num',$row2->verse);
  }
  // Send results back to JavaScript Client
  echo $xmlDoc->saveXML();
  // Close the connection
  mysql_close($DB_Connection);
}

Despite my remarks on the role of PHP, I enjoy PHP programming a lot. It’s is a great and powerful language. My next post will discuss the script above…

The Key to Everything…

TheHolyScriptures.info uses the “AJAX” technique on the client side (xhtml, CSS, JavaScript) to communicate with the server side (PHP, MySQL) and is the key to everything that allows the page to interact with the database. The communication occurs by using the XMLHttpRequest object. Here is the function I use to create my XMLHttpRequest object:

function getNewXMLHttpRequest() {
  var Obj = false;
  try {
    // For Firefox, Safari, Chrome, Opera, IE7+
    Obj = new XMLHttpRequest();
  } catch (trymicrosoft) {
    try {
      Obj = new ActiveXObject('Msxml2.XMLHTTP');
    } catch (othermicrosoft) {
      try {
        Obj = new ActiveXObject('Microsoft.XMLHTTP');
      } catch (failed) {
        try {
          AJAX = window.createRequest();
        } catch (e) {
          Obj = false;
          alert('XMLHttpRequest Error! Your Browser is incompatible.');
        }
      }
    }
  }
  return Obj;
}

… and below is an example of actual usage – in this case a POST (update) to the server. If I tried to do this by tacking my params onto the url and using a GET, my commentaryText variable would be limited in size to about 4k and would get truncated. So I always use a POST when writing to the server and a GET when reading from the server, just like the names imply. Reasons for always doing it this way include: consistency, security with POST writes, no size limitations with POST writes, and client side caching with GET reads.

if (!AJAX) AJAX = getNewXMLHttpRequest();
var url = "PHP/SaveComment.php";
var params = "id=" + CVERSEID + "&type=" + CTYPE + "&name=" + CNAME;
params += "&cmd=" + sqlCommand + "&comment=" + commentaryText;
AJAX.open('POST', url, true);
AJAX.setRequestHeader("Content-type", "application/x-www-form-urlencoded");
AJAX.setRequestHeader("Content-length", params.length);
AJAX.onreadystatechange = function() { ReShowCommentary(myCommands); };
AJAX.send(params);

For completeness a GET example is shown below. The GET is actually a bit simpler than the POST. Not much code really. Note that the param’s are part of the url. Also the callback routine (populateDisplay) is specified with no arguments, but just because it’s not needed in this case.

 if (!AJAX) AJAX = getNewXMLHttpRequest();
 var url = 'PHP/Lookup_XML.php?vol=' + escape(volume) + "&book=" + escape(book);
 AJAX.open('GET', url, true);
 AJAX.onreadystatechange = populateDisplay;
 AJAX.send(null);

The last AJAX step is to actually receive data. This involves a little dance step in the callback routine looking for the right events before proceeding. We just have to wait for the right readyState and status before grabbing the data string from AJAX.responseText

function populateDisplay() {
  if (AJAX.readyState == 4) {
    if (AJAX.status == 200) {
      var myXML = XMLparse(AJAX.responseText);
      // put code here to use the XML document
    }
  }
}

Well, to be complete I guess I should go a little further with this. The data is coming back as a XML string but it must be defined as such if we’re going to use it. The responseText is just a string. It could be any type of string but passing XML around makes a heck of a lot of sense if responseText contains anything complicated at all. In the case of scripture data there are volumes, books, chapters, verses – each with meta-data so using XML is a no brainer. By using XML we have a larger string being passed in but the increased size of the string is not a good reason to avoid XML. If the data string is small, then a few extra XML tags just aren’t significant and if the data string is large then the XML tags are just a small percentage of the total size but all the more important. The meta-data is never a waste and is always used or I wouldn’t be sending it.

function XMLparse(text) {
  if (typeof DOMParser != "undefined") {
    // Mozilla, Firefox, and related browsers
    return (new DOMParser()).parseFromString(text, "application/xml");
  } else if (typeof ActiveXObject != "undefined") {
    // Internet Explorer.
    var doc = XMLnewDocument( );    // Create an empty document
    doc.loadXML(text);              // Parse text into it
    return doc;                     // Return it
  }
}

Well, that’s it for the AJAX I use in JavaScript. In others posts, I’ll discuss the PHP server side of this AJAX communication and also how I access and use the client side XML.