zoukankan      html  css  js  c++  java
  • 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解析函数中进行拦截处理就好了。
  • 相关阅读:
    小毛病,大问题
    [zz]Libvirt 虚拟化库剖析
    libvirt XML 学习笔记
    Ubuntu 10.04下使用 libvirt 创建KVM虚拟机
    [zz]使用libvirt管理kvm虚拟机(更新中)
    [zz]LXC:Linux 容器工具
    一些比较好的URL
    [zz]Libvirt XML学习笔记
    [zz]一些KVM xml 例子
    [zz]kvm环境使用libvirt创建虚拟机
  • 原文地址:https://www.cnblogs.com/xyyt/p/13039170.html
Copyright © 2011-2022 走看看