• 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解析函数中进行拦截处理就好了。
  • 相关阅读:
    centos crash debug
    go get Unknown SSL protocol error in connection to gopkg.in
    Tensorflow serving with Kubernetes
    Spring 集成 Swagger UI
    Docker Registry V2 Garbage Collection
    Docker Registry V2 with Nginx
    Zabbix磁盘性能监控
    Zabbix CPU utilization监控参数
    Windows挂载Gluster复制卷
    Redis持久化存储(三)
  • 原文地址:https://www.cnblogs.com/xyyt/p/13039170.html
Copyright © 2020-2023  润新知