title: Text node numbering and replacement for database indexing not sure how robust this would be
body: <p>Look for ++++ if you just want to see the code - preamble is just for context.</p>
  
  <p><strong>pre-amble / explanation</strong></p>
  
  <p>I am building an <strong>offline</strong> knowledge base for a client (i.e. entirely javascript with off-line ability to add pages - so can't use appcache for page content).</p>
  
  <p>I have a WYSIWYG editor and was going to store the HTML version of the document and a stripped version (all HTML tags removed) separately in indexedDB/WebSQL (with the text version being used to search for key terms).</p>
  
  <pre><code>id    html    plain_text     //schema simplified
  </code></pre>
  
  <p>After a bit of thought I decided that it would be better to traverse all the text nodes and store each one of those in the database. Then replace the node text with ((X)) where X is the number of that node.</p>
  
  <pre><code>ID    pageID    NodeID    NodeText
  </code></pre>
  
  <p>and a second table </p>
  
  <pre><code>pageID    HTML 
  </code></pre>
  
  <p>This seems to be the most efficient way to store the text for searches (as I can store each text nodes text in a separate row in the database rather than 1 huge block).</p>
  
  <p>(FOR CLARITY)</p>
  
  <pre><code>&lt;div id="cheese"&gt;Magical Content&lt;/div&gt;
  &lt;ul&gt;&lt;li&gt;mystical content&lt;/li&gt;&lt;/ul&gt;
  </code></pre>
  
  <p>would become</p>
  
  <pre><code>&lt;div id="cheese"&gt;((0))&lt;/div&gt;
  &lt;ul&gt;&lt;li&gt;((1))&lt;/li&gt;&lt;/ul&gt;    
  </code></pre>
  
  <p>with an array containing </p>
  
  <pre><code>0 =&gt; "Magical Conten", 1 =&gt; "mystical content"
  </code></pre>
  
  <p>That could then be stored in the database and used to reconstruct the page using the second version of the HTML.</p>
  
  <p>++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++</p>
  
  <p><strong>The Code bit if you want to skip the preamble that is only there for illustration of the 'why' (in case someone tells me I am an idiot and has a better suggestion!)</strong></p>
  
  <p>Easiest way to see what I mean is to <a href="http://jsfiddle.net/hdbmugcz/5/" rel="nofollow">check the fiddle</a></p>
  
  <p>Comment out <code>'convertNodeBack(div);</code> at the end to see what I mean about replacing text nodes with ((0)), ((1)) etc.</p>
  
  <p>Check the console to see the array of text elements.</p>
  
  <p>Then uncomment and re-run and the text should be replaced in the correct places. It seems to work ok and is fairly fast.</p>
  
  <p><strong>My question is</strong></p>
  
  <p>how robust is this as a solution - has anyone tried anything similar and come across any strange cases / edge cases?? </p>
  
  <p>Are there any cases where this won't work as expected?</p>
  
  <p>Thanks in advance.</p>
  
  <p><strong>JS Just incase anything happens to the fiddle (as I HATE link only questions!!)</strong></p>
  
  <pre><code>var start = new Date().getTime(); 
  
  var textNodes = [];
  
  //node, do you want a single string output or an array, do you want to match empty nodes?
  function getTextNodesIn(node, singleString, includeWhitespaceNodes) {
  var nonWhitespaceMatcher = /\S/;
  //singlestringtext is used for a single string with all the page words.
  var singleStringText = "";
  //counter for the number of matches.
  var counter = 0;
  
  function getTextNodes(node) {
  
      if (node.nodeType == 3) {
          if (includeWhitespaceNodes || nonWhitespaceMatcher.test(node.nodeValue)) {
              //remove line breaks and trim the string.
              var itemText = node.textContent.replace(/(\r\n|\n|\r)/gm,"").trim();
  
              if(singleString){
                  singleStringText += itemText + " ";
              }else{
                  textNodes[counter] = itemText;
                  node.nodeValue = "((" + counter + "))";
                  counter ++;
              }
  
          }
      } else {
          for (var i = 0, len = node.childNodes.length; i &lt; len; ++i) {
              getTextNodes(node.childNodes[i]);
          }
      }
  }
  
  getTextNodes(node);
   if(singleString){
                  return singleStringText;
              }else{
                 return textNodes;
              }
  
  }
  
  
  //converts a given document back to original
  function convertNodesBack(node, singleString, includeWhitespaceNodes) {
  var nonWhitespaceMatcher = /\S/;
  var singleStringText = "";
  var counter = 0;
  
  function getTextNodes(node) {
  
      if (node.nodeType == 3) {
          if(node.nodeValue.match(/\(\(([^)]+)\)\)/g)){
              var nodeNumber = node.nodeValue.replace(/[()]/g,'');
  
             node.nodeValue = textNodes[counter];
                  counter ++;
          }
      } else {
          for (var i = 0, len = node.childNodes.length; i &lt; len; ++i) {
              getTextNodes(node.childNodes[i]);
          }
      }
  }
  
  getTextNodes(node);
   if(singleString){
                  return singleStringText;
              }else{
                 return textNodes;
              }
  
  }
  
  
  
  //convert page to node text mode.
  var div =  document.getElementById('bodyText');
  getTextNodesIn(div);
  
  //convert page back to text from node text mode.
  var div =  document.getElementById('bodyText');
  convertNodesBack(div);
  console.log(textNodes);
  
  console.log(new Date().getTime() - start);
  </code></pre>