jQuery XML 解析器和搜索机制

2016-10-18    蓝蓝设计的小编

如果您想订阅本博客内容,每天自动发到您的邮箱中, 请点这里

 

介绍

这里所描述的过程将使你能够创建一个简单的基于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;
    }
}
 
 
 

 蓝蓝设计www.lanlanwork.com )是一家专注而深入的界面设计公司,为期望卓越的国内外企业提供卓越的UI界面设计BS界面设计  cs界面设计  ipad界面设计  包装设计  图标定制  用户体验 、交互设计、 网站建设 平面设计服务 

 

日历

链接

个人资料

蓝蓝设计的小编 http://www.lanlanwork.com

存档