vue項目快速實現后端接口返回的xml格式的數據進行解析


相關背景:

老項目重構,后端返回xml格式數據。

前端有現有的vue項目底層框架可以復用,現有框架支持對后端返回的json數據進行解析,需要調整的就是對xml格式數據的解析。

前端對后端接口的請求使用axios進行封裝,且有mock數據方便本地聯調開發。

解決方案:

封裝xml解析相關方法;

根據后端接口返回數據格式邊寫xml文件進行后端數據mock;

mock數據的實現:

json格式的數據可以直接編寫json格式的數據進行模擬,可以很方便的進行解析。

xml格式的數據如果直接寫成字符串格式的,更新管理起來會比較麻煩,因此可以直接編寫xml文件進行模擬。

對於mock接口數據的xml文件,可以在mock數據請求封裝中直接對xml文件進行讀取解析。

xml解析相關函數封裝:

xmlLoad.js

 1 /**
 2  * 加載xml文件
 3  * @param {Object} dname
 4  */
 5 function loadXMLDoc(dname) {
 6   let xhttp
 7   if (window.XMLHttpRequest) {
 8     xhttp = new XMLHttpRequest();
 9   } else {
10     xhttp = new ActiveXObject("Microsoft.XMLHTTP");
11   }
12   xhttp.open("GET", dname, false);
13   xhttp.send();
14   return xhttp.responseXML;
15 }
16 
17 /**
18  * xml字符串轉換xml對象數據
19  * @param {Object} xmlStr
20  */
21 function xmlStr2XmlObj(xmlStr) {
22   var xmlObj = {};
23   if (document.all) {
24     var xmlDom = new ActiveXObject("Microsoft.XMLDOM");
25     xmlDom.loadXML(xmlStr);
26     xmlObj = xmlDom;
27   } else {
28     xmlObj = new DOMParser().parseFromString(xmlStr, "text/xml");
29   }
30   return xmlObj;
31 }
32 
33 /**
34  * xml直接轉換json數據
35  * @param {Object} xml
36  */
37 function xmlObj2json(xml) {
38   try {
39     var obj = {};
40     if (xml.children.length > 0) {
41       for (var i = 0; i < xml.children.length; i++) {
42         var item = xml.children.item(i);
43         var nodeName = item.nodeName;
44         if (typeof(obj[nodeName]) == "undefined") {
45           obj[nodeName] = xmlObj2json(item);
46         } else {
47           if (typeof(obj[nodeName].push) == "undefined") {
48             var old = obj[nodeName];
49             obj[nodeName] = [];
50             obj[nodeName].push(old);
51           }
52           obj[nodeName].push(xmlObj2json(item));
53         }
54       }
55     } else {
56       obj = xml.textContent;
57     }
58     return obj;
59   } catch (e) {
60     console.log(e.message);
61   }
62 }
63 
64 /**
65  * xml字符串轉換json數據
66  * @param {Object} xml
67  */
68 function xmlStr2json(xml) {
69   var xmlObj = xmlStr2XmlObj(xml);
70   var jsonObj = {};
71   if (xmlObj.childNodes.length > 0) {
72     jsonObj = xmlObj2json(xmlObj);
73   }
74   return jsonObj;
75 }
76 
77 export default {
78   loadXMLDoc,
79   xmlStr2XmlObj,  
80   xmlObj2json,
81   xmlStr2json
82 }

mock后端返回數據:

mocklist.xml

<?xml version="1.0" encoding="utf-8"?>

<Apilist>
  <!--首頁banner-->
  <searchBanners>
    <ApiResult>
      <ret_code>000000</ret_code>
      <ret_msg>請求成功</ret_msg>
      <datas>
        <Banner>
          <banner_id>001</banner_id>
          <set_id>001</set_id>
          <num>0</num>
          <pic_url>http://xxx.com.jpg</pic_url>
          <link_type>0</link_type>
          <link_id>http://xxx.com</link_id>
          <description>描述</description>
        </Banner>
        <Banner>
          <banner_id>002</banner_id>
          <set_id>002</set_id>
          <num>0</num>
          <pic_url>http://xxx.com.jpg</pic_url>
          <link_type>1</link_type>
          <link_id>/myTask</link_id>
          <description>描述</description>
        </Banner>
      </datas>
    </ApiResult>
  </searchBanners>
  ...
</Apilist>

如上,高亮部分的標簽可以看做是mock接口的名稱,與前端對接口請求的封裝函數名對應,如下:

request.js

import request from '@api/request'
const {
  errorToast,
  http
} = request
/**
 * 導出接口請求
 * noNeedLogin: true 無需登錄
 * noPreError: true 無需預處理錯誤信息
 */
export default {
  errorToast,
  //檢驗用戶登錄有效性
 searchBanners(params) {
    return http({
      api: "searchBanners",
      data: params
    })
  },
......

注:經驗證,xml文件需要放在static文件夾中,本地編譯vue項目后,能直接在瀏覽器中訪問該文件,以便於xml文件的讀取。

xml文檔中mock數據的讀取:

request.js

 1 import axios from "axios"
 2 ......
 3 import xmlLoad from '@assets/js/xmlLoad'
 4 /**
 5  * 封裝mock數據模擬接口請求
 6  */
 7 let http2;
 8 if (isLocal) http2 = (params) => {
 9   var self = this
10   let dname = location.origin + '/static/mocklist.xml'
11   return new Promise((resolve, reject) => {
12     //讀取xml中的數據
13     let xmlNodes = xmlLoad.loadXMLDoc(dname) //xml數據讀取
14     if(!xmlNodes) return;
15     let xmlJson = xmlLoad.xmlObj2json(xmlNodes) //xml轉換為json格式數據
16     let mocklist = xmlJson['Apilist'] //mock數據列表
17     setTimeout(() => {
18       //獲取當前訪問接口名及mock數據
19       let key = params.api
20       var data = mocklist[key].ApiResult 
21       resolve(data)
22   })
23 }
24 
25 export default {
26   errorToast,
27   http: isLocal ? http2 : http
28 }

后端接口真實數據的讀取:

request.js

 1 import axios from "axios"
 2 import xmlLoad from '@assets/js/xmlLoad'
 3 ......
 4 
 5 /**
 6  * 封裝服務器端接口請求方法
 7  */
 8 const http = (params) => {
 9   return new Promise((resolve, reject) => {
10     axios.request({
11       url: '/xxxx.do',//后端訪問接口地址
12       params: params.data,
13       method: params.method || 'POST'
14     }).then(function(res) {
15       //解析接口返回的xml字符串數據
16       let xmlStr = res.data;
17       let xmlJson = xmlLoad.xmlStr2json(xmlStr)
18       let data = xmlJson && xmlJson["ApiResult"]
19       if (res.status == 200 && data) {
20         ......
21         resolve(data)
22       } else {
23         errorToast();
24         console.log(data)
25       }
26     }).catch(function(e) {
27       errorToast();
28       reject(e)
29     });
30   })
31 }
32 
33 /**
34  * 封裝mock數據模擬接口請求
35  */
36 let http2;
37 ......
38 
39 export default {
40   errorToast,
41   http: isLocal ? http2 : http
42 }

如上,即實現了對后端接口數據的模擬,方便本地開發,同時對xml格式數據處理方面也只是在請求封裝中進行,頁面中的實現未受影響。

注意事項:

對於xml到json的轉換,因xml本身並沒有數組的概念,所以需要注意我們需要的“數組”如果只有一條數據的異常處理。

1       <datas>
2         <UserTask>
3           <task_tag>001</task_tag>
4           <task_term>001</task_term>
5           <task_title>xxxx</task_title>
6           <task_status>0</task_status>
7           <task_extra_info>{"tag_name":"xxxx","tag_pic_url":"https://xxxx.jpg","task_begin_time":"2020.06.20","task_end_time":"2020.07.20"}</task_extra_info>
8         </UserTask>
9       </datas>

如上面代碼,如果只有一個 UserTask ,那么解析出來將是一個Object對象:

//只有一個UserTask
data:{
    UserTask:{
        ......
    }
}

如果有多個,則是數組:

//有多個UserTask
data:{
    UserTask:[{
        ......
    },{
        ......
    },{
        ......
    }]
}

對於這個情況,可以封裝一個函數進行轉換,以方便前端進行頁面布局與數據渲染。代碼如下:

 1 /**
 2  * xml解析后的列表轉換為js的數組
 3  * @param {Object} xmlList
 4  */
 5 function xmlListToArr(xmlList) {
 6   let targetArr = []
 7   if (xmlList.constructor == Array) {
 8     targetArr = xmlList
 9   } else {
10     targetArr[0] = xmlList
11   }
12   return targetArr
13 }

如上,可以封裝在公共函數里邊,在頁面中有從后端請求的列表數據需要渲染時,就可以調用這個函數進行數據處理。

這里還需要注意這些問題:

  • 大部分列表數據都需要進行數組化處理:畢竟大部分列表的數據都當然,如果是幾個簡單的圖片列表的展示,那可以考慮單個圖片的展示,不必要把單個圖片也轉換成數組;
  • 數組化處理操作在具體頁面具體業務代碼中進行:列表數據的處理由於xml中沒有數組的概念,所以沒辦法很好的進行集中封裝處理,因此可以在具體頁面的具體數據進行處理;
  • 可以集中封裝處理的情況:如果知道后端返回接口所有列表類數據都嚴格包含某個字符串,如list,那么可以直接在xml解析函數中進行攔截處理就好了。

 


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM