jQuery XML 解析器和搜尋機制

2016-10-23    分類:WEB開發、程式設計開發、首頁精華0人評論發表於2016-10-23

本文由碼農網 – 小峰原創翻譯,轉載請看清文末的轉載要求,歡迎參與我們的付費投稿計劃

下載 jQuery-XML-parser-and-search.zip – 9.5 KB

介紹

這裡所描述的過程將使你能夠建立一個簡單的基於jQuery / XML的解析器和搜尋機制。此過程將通過一個AJAX請求檢索XML,然後在jQuery中分析資料,為搜尋機制做準備。該解決方案將基於不區分大小寫的全部或部分關鍵字匹配地返回結果。來自於關鍵字搜尋的返回結果設定將被格式化為一個直接連結到相應網站的超連結。jQuery搜尋方法非常類似於Mike Endale的一個專案,不過增加了一個DOM解析器,正規表示式以及結果集分組。

背景

客戶端需要一個簡單的搜尋工具來查詢基於關鍵字搜尋的本地內部網站。關鍵字搜尋必須不區分大小寫,並允許返回部分匹配的結果。歸咎於客戶端內容管理系統的架構,因此(SharePoint)只能執行客戶端指令碼。其解決方案的另一個障礙是,源資料將來自多個源。資料被儲存在多個Excel電子表格,CSV檔案和MS Access資料庫內。這就對我們提出了這樣的需要:開發具有一系列查詢和一個巨集的Access解決方案,充當可合併、擦洗,並最後格式化資料作為XML輸出的偽ETL。對於這個解決方案的目的,我們將詳細介紹JavaScript XML分析器的設計,而不是偽Access ETL巨集工具的設計。

使用程式碼

該解決方案的做法是利用一個簡單的基於JavaScript / XML的搜尋來傳送資料結果到HTML / JavaScript前端。前端將引用指令碼:jQuery,XML和CSS檔案。XML格式將因為它的可讀性和它是資料交換行業標準格式之一的事實而被使用。 XML資料將通過使用AJAX的客戶端jQuery解析,並通過Internet Explorer 11呈現。

解決方案將使用RegExp物件來處理關鍵字匹配,驗證和特殊字元處理。RegExp物件字串將檢查危險語法從而提高解決方案的穩定性和整體可用性。

我們將預設使用JavaScript分組功能來返回匹配結果作為摺疊的紀錄集。摺疊的記錄集線專案將被URL連結到相關的Project Workspace網站。在擴充套件的組記錄集下,結果將存在於相關的子記錄中,當通過On Click事件展開的時候。

資訊架構

解析器函式有一個複雜的帶有節點和屬性的層次XML樹,並且將它轉變成等價的JavaScript物件和屬性。客戶端基於JavaScript / XML的搜尋需要經過以下步驟:

1.偽ETL工具準備資料到XML檔案(本專案不包括這一步驟)

2.此XML檔案載入到指定的位置(本專案不包括這一步驟)

3.在點選事件發生時,JavaScript解析器將使用AJAX方法載入XML資料

4.檢查搜尋中關鍵字的存在

  • 如果沒有關鍵字存在丟擲錯誤訊息“Please enter a search keyword”

5.如果有節點包含URL屬性的字串,那麼節點加入到陣列中。

6.RegExp物件關鍵字通過替代匹配特殊字元處理

7.RegExp物件關鍵字匹配轉換為不區分大小寫

8.迴圈陣列匹配基於驗證的RegExp物件

  • 如果沒有結果,那就丟擲錯誤訊息“No results were found!”

9.用斑馬條紋的奇數和偶數行對頂級組構建結果集

10.用相關的Work Order構建組匹配PPID行作為子組

11.填充結果,然後將它們傳遞到最後呈現的集合

12.顯示具有列和所有分組標題的結果集合

  • 分組在預設情況下摺疊

使用者介面

使用者介面是一個簡單的基於HTML / JavaScript客戶端搜尋來返回關鍵字匹配結果——預設為摺疊和分組的記錄集合。以行專案顯示的摺疊紀錄集合直接URL連結到相關專案的網站。在擴充套件組記錄集合下,結果在On Click事件擴大時將保留相關的子記錄。

內嵌頁面引用

我們需要做的第一件事是引用我們的指令碼:jQuery,XML和CSS檔案。

<link rel="stylesheet" href="path/default.css" />
<script type="text/javascript" src="path/jquery-1.4.2.min.js"></script>
<script id="data" type="text/javascript" src="path/search.js" xmlData="data.xml"></script>
<input id="term" type="text"/> < input name="Search" id="searchButton" type="button" value="Search"/>
<div id="result">< /div>

你會發現我們已經新增了xmlData屬性到search.js引用。這是傳遞來自於HTML檔案的XML檔案位置的最佳方式。如果你有你有多個專案xml檔案想要用作為資料來源的話,那麼這就很有幫助。

XML資料來源

XML資料來源可以以任何方式或任何大小來構造;但建議保持源XML檔案小於1 MB,以便於保持適當的分析器響應時間。下面是XML源用於此專案的一個例子:

<?xml version="1.0" encoding="UTF-8"?>
<dataroot generated="2015-11-20T10:30" xmlns:od="urn:schemas-microsoft-com:officedata"> 
<etl>
<PPID Lead="Slow,Roy" Description="NORTH OF FAIR" PID="P002">
  <WO Description="SHELTON - BANK (SAFETY)" PM="Slow,Roy" Status="CLOSED" WID="305577" WOXREF="SHEL" Program="REINFORCEMENT">
</WO>
  <Archive>Archived</Archive> 
  <record search="P002NORTH OF FAIRSHELSHELTON 305577SHELTON - BANK (SAFETY)Slow,Roy"/>
  <url address="P002"/>
</PPID>
</etl>
</dataroot>

錯誤處理

對於這個專案,我們已經在兩個關鍵領域使用過錯誤處理。如果沒有關鍵字存在,那麼錯誤訊息“Please enter a search keyword”將出現。如果沒有個結果生成,則丟擲錯誤訊息“No results were found!”。

//Check if a keyword exists
    if (keyword == '') {
      errMsg += 'Please enter a search keyword';
    } else {
      searchThis();
    }
if (i == 0) {
pub += '< div>';
pub += 'No results were found!';
pub += '< /div>';

使用jQuery AJAX請求

我們將通過預定義的能在頁面級別啟用的jQuery庫通過非同步JavaScript函式呼叫XML。 AJAX的全稱是“異Asynchronous JavaScript and XML”,由Jesse James Garrett,Adaptive Path的創始人所杜撰。AJAX依賴於XMLHttpRequest,CSS,DOM和其他技術。AJAX的主要特點是它的“非同步”性質,這意味著它可以從伺服器而無需重新整理頁面來傳送和接收資料。在非同步模式中,客戶端和伺服器會獨立地工作,以及獨立地進行通訊,從而允許使用者持續與網頁互動,不管伺服器上發生了什麼。

function searchThis() {
  $.ajax({
    type: "GET",
    url: XMLSource,
    dataType: "xml",
    success: function (xml) {
      loadPublication(xml)
    }
  });
}

使用DOM解析和正規表示式

由於jQuery本身不能解析XML字串;我們將充分利用瀏覽器的DOM解析方法——大多數瀏覽器以這種或那種形式支援。火狐,Chrome,Safari以及最新的Internet Explorer瀏覽器均支援這種方法,它們都具有DOMParser物件。較早的Internet Explorer瀏覽器(如IE 8)使用其專有的ActiveX物件。可以建立跨瀏覽器的解決方案,來檢查是否缺少DOMParser,但這超出了這個專案的範圍,但是可能以後在額外的跨瀏覽器支援中會新增。

知道JavaScript RegExp(正規表示式)功能和語法來處理任意特殊字元。同時通過定義正規表示式來忽略大小寫,以便於在關鍵字搜尋時更加友好。

function loadPublication(xmlData) {
  i = 0;
  var row;
  var searchExp = "";
  var ppid = "P";

  $(xmlData).find('PPID').each(function () {

          // Check if a site URL attr exists
          if($(this).find('url').attr('address').length) {

              //Set the search string Variables
              var record          = $(this).find('record').attr('search');
              var archive         = $(this).find('Archive');

              //Escape characters in keyword expression and use global match
              RegExp.escape = function(keyword) {
              return keyword.replace(/[\-\[\]\/\{\}\(\)\*\+\?\.\\\^\$\|]/g, "\\$&");
              };

              //Keyword expression will be case agnostic
              var exp = new RegExp(keyword, "i");

              //Use formated keyword as the default search
              searchExp = record.match(exp);

              //If the search expression is not null
              if (searchExp != null) {

              //Start building the result
              if ((i % 2) == 0) {
              row = 'even';
              } else {
              row = 'odd';
              }

              if($(this).attr('PID') != ppid) {
                  ppid = $(this).attr('PID');

                  i++;

分組返回結果

使用者介面是一個簡單的基於HTML / JavaScript客戶端搜尋來返回關鍵字匹配結果預設為摺疊又分組的記錄集合。以行專案顯示的摺疊紀錄集合直接URL連結到相關專案的網站。在擴充套件組記錄集合下,結果在On Click事件擴大時將保留相關的子記錄。

//Grouping of the results
function expgroupby(e) {
	docElts=document.all;
	numElts=docElts.length;
	images = e.getElementsByTagName("IMG");
	img=images[0];
	srcPath=img.src;
	index=srcPath.lastIndexOf("/");
	imgName=srcPath.slice(index+1);
	var b="auto";
	if(imgName=="plus.gif"){
		b="";
		img.src="/_layouts/images/minus.gif"
	}else{
		b="none";
		img.src="/_layouts/images/plus.gif"
	}
	oldName=img.name;
	img.name=img.alt;
	spanNode=img;
	while(spanNode!=null){
		spanNode=spanNode.parentNode;
		if(spanNode!=null&&spanNode.id!=null&&spanNode.id=="wrapper")break
	}

	while(spanNode.nextSibling!=null&&spanNode.nextSibling.id!="wrapper"){
		spanNode=spanNode.nextSibling;
		spanNode.style.display=b;
	}
}

完整的原始碼

下面是這個專案完整的原始碼例子。

//Full source
$(document).ready(function () {

//Global Variables
  var XMLSource = $('#data').attr('xmlData');
  var keyword = '';
  var pub = '';

  var i = 0;

  $("#searchButton").click(function () {
    keyword = $("input#term").val();

//Reset any message
    var errMsg = '';
    pub = '';

//Check if a keyword exists
    if (keyword == '') {
      errMsg += 'Please enter a search keyword';
    } else {
      searchThis();
    }

    if (errMsg != '') {
      pub += '< div>';
      pub += errMsg;
      pub += '< /div>';
    }

//Show error
    $('#result').html(pub);

  });

//Use enter key to trigger the search query  
	$("input#term").keypress(function (e) {
	var key = e.which;
	if (key == 13){
     $("#searchButton").click();
     return false;
	}
  });

  function searchThis() {
    $.ajax({
      type: "GET",
      url: XMLSource,
      dataType: "xml",
      success: function (xml) {
        loadPublication(xml)
      }
    });
  }

  function loadPublication(xmlData) {
    i = 0;
    var row;	
    var searchExp = "";
    var ppid = "P";     

    $(xmlData).find('PPID').each(function () {
	// Check if a site URL attr exists		
	if($(this).find('url').attr('address').length) {

	var record 	= $(this).find('record').attr('search');
	var archive	= $(this).find('Archive');			

	//Escape characters in keyword expression and use global match	
	RegExp.escape = function(keyword) {
	return keyword.replace(/[\-\[\]\/\{\}\(\)\*\+\?\.\\\^\$\|]/g, "\\$&");
				};

	//Keyword expression will be case agnostic
	var exp = new RegExp(keyword, "i");

      	//Use formated keyword as the default search
        	searchExp = record.match(exp);

 	//If the search expression is not null
      	if (searchExp != null) {

        	//Start building the result
        	if ((i % 2) == 0) {
          	row = 'even';
        		} else {
          	row = 'odd';
        		}

        		if($(this).attr('PID') != ppid) {
        			ppid = $(this).attr('PID');

        			i++;

	//Grouped header row with URL links from the xml attr
	pub += '< tr id="wrapper"code-string" style="margin: 0px; padding: 0px; border: 0px; color: rgb(128, 0, 128);">'">'	
	+ '< td colspan="8">'
	+ '< a onclick="javascript:expgroupby(this);return false;" href="javascript:">'
	+ '< img name="collapse" alt="expand" src="/_layouts/images/plus.gif" border="0" />< /a>'
	+ '< a href="http://project.com/sites/tp/Projects/' + $(this).find('url').attr('address') + '">' + '  ' + $(this).attr('PID')+ ' - ' + $(this).attr('Description') + ' - ' + $(this).attr('Lead') + '< /a>< /td>'
	+ '</tr>';

	}

	  //Bottom grouped expand detail fields
	pub += '<tr id="item" style="display: none;">'
	+ '< td valign="top">' + $(this).find('WO').attr('WID') + '< /td>'
	+ '< td valign="top">' + $(this).find('WO').attr('Description') + '< /td>'
	+ '< td valign="top">' + $(this).find('WO').attr('PM') + '< /td>'
	+ '< td valign="top">' + $(this).find('WO').attr('Status') + '< /td>'
	+ '< td valign="top">' + $(this).find('WO').attr('WOXREF') + '< /td>'
	+ '< td valign="top">' + $(this).find('WO').attr('Program') + '< /td>'
	+ '< td valign="top">' + $(this).find('Archive').text() + '< /td>'
	+ '< /tr>';			
		}
	}
});

    if (i == 0) {
      pub += '< div>';
      pub += 'No results were found!';
      pub += '< /div>';

      //Populate the result
      $('#result').html(pub);
    } else {
      //Pass the result set
      showResult(pub);
    }
  }

  function showResult(resultSet) {

    //Show the result with the titles of the column fields
	pub = '< div>There are ' + i + ' results!< /div>';
	pub += '< table id="grid" border="0">';
	pub += '< thead>< tr>< td>< th>PPID - Project Description - Lead PM< /th>< /td>< /tr>';
	pub += '< tr>< th>WO Number< /th>';
	pub += '< th>WO Description< /th>';
	pub += '< th>Project Manager< /th>';
	pub += '< th>Status< /th>';
	pub += '< th>XRef< /th>';
	pub += '< th>Program< /th>';
	pub += '< th>Archive Status< /th>';
	pub += '< /tr>< /thead>';
	pub += '< tbody>';

	pub += resultSet;

	pub += '< /tbody>';
	pub += '< /table>';

    //Populate the results
    $('#result').html(pub)

    $('#grid').tablesorter();
  }
});

//Grouping of the results
function expgroupby(e) {
	docElts=document.all;
	numElts=docElts.length;
	images = e.getElementsByTagName("IMG");
	img=images[0];
	srcPath=img.src;
	index=srcPath.lastIndexOf("/");
	imgName=srcPath.slice(index+1);
	var b="auto";
	if(imgName=="plus.gif"){
		b="";
		img.src="/_layouts/images/minus.gif"
	}else{
		b="none";
		img.src="/_layouts/images/plus.gif"
	}
	oldName=img.name;
	img.name=img.alt;
	spanNode=img;
	while(spanNode!=null){
		spanNode=spanNode.parentNode;
		if(spanNode!=null&&spanNode.id!=null&&spanNode.id=="wrapper")break
	}

	while(spanNode.nextSibling!=null&&spanNode.nextSibling.id!="wrapper"){
		spanNode=spanNode.nextSibling;
		spanNode.style.display=b;
	}
}

許可證

這篇文章以及任何相關的原始碼和檔案遵循 The Code Project Open License (CPOL)。

譯文連結:http://www.codeceo.com/article/jquery-xml-parser-and-search.html
英文原文:jQuery XML Parser and Search
翻譯作者:碼農網 – 小峰
轉載必須在正文中標註並保留原文連結、譯文連結和譯者等資訊。]

相關文章