类名 common/service/Utils.js
import {
  Extent,
  Geometry,
  Polygon,
  SpatialReference,
  LineString,
  MultiLineString,
  Point,
  Circle,
  MultiPolygon,
  MultiPoint
} from '../base/geometry'
import Log from '../util/Log'
import { defaultValue, isBoolean, isNull, isNumber, isString } from '../util'
import { Color, Feature, FeatureSet } from '../base'

/**
 * @private
 * @description 获取查询参数字符串
 * @param fields 字段名数组
 * @param options 查询参数
 * @param checkOptions 检测规则
 * @return String GUID
 */
function getParameters(fields, options, checkOptions) {
  let url = ''
  for (let i = 0; i < fields.length; i++) {
    // 获取查询条件
    const _filter = defaultValue(
      options[fields[i]],
      checkOptions[fields[i]].default
    )
    // 必须不为空
    if (_filter !== undefined) {
      let str = ''
      // 没有process参数,走类型判断
      if (isNull(checkOptions[fields[i]].process)) {
        // 根据类型进行数据处理
        switch (checkOptions[fields[i]].type) {
          case 'String':
          case 'Number':
          case 'Boolean':
            url += `&${
              checkOptions[fields[i]].alias || fields[i]
            }=${encodeURIComponent(_filter)}`
            break
          case 'Geometry':
          case 'Point':
          case 'MultiPoint':
          case 'Extent':
          case 'Circle':
          case 'LineString':
          case 'MultiLineString':
          case 'Polygon':
          case 'MultiPolygon':
            url += `&${fields[i]}=${encodeURIComponent(
              _filter.toString()
            )}&geometryType=${encodeURIComponent(_filter.getIGSType())}`
            break
          case 'layerDefs':
            str = '['
            for (let i = 0; i < _filter.length; i++) {
              if (
                _filter[i] instanceof Object &&
                !(_filter[i] instanceof Array)
              ) {
                str += '{'
                Object.keys(_filter[i]).forEach((key) => {
                  if (_filter[i].hasOwnProperty(key)) {
                    str += `"${key}":"${_filter[i][key]}",`
                  }
                })
                str = str.substring(0, str.length - 1)
                str += '},'
              }
            }
            if (_filter.length > 0) {
              str = str.substring(0, str.length - 1)
            }
            str += ']'

            if (str !== '[]') {
              url += `&${fields[i]}=${encodeURIComponent(str)}`
            }
            break
          case 'OutStatistics':
            str += '['
            for (let i = 0; i < _filter.length; i++) {
              if (
                _filter[i] instanceof Object &&
                !(_filter[i] instanceof Array)
              ) {
                str += '{'
                Object.keys(_filter[i]).forEach((key) => {
                  if (_filter[i].hasOwnProperty(key)) {
                    if (
                      key === 'statisticType' ||
                      key === 'onStatisticField' ||
                      key === 'outStatisticFieldName'
                    ) {
                      str += `"${key}":"${_filter[i][key]}",`
                    }
                  }
                })
                str = str.substring(0, str.length - 1)
                str += '},'
              }
            }
            if (_filter.length > 0) {
              str = str.substring(0, str.length - 1)
            }
            str += ']'

            if (str !== '[]') {
              url += `&${fields[i]}=${encodeURIComponent(str)}`
            }
            break
          case 'FeatureSet':
            str = `&${fields[i]}=${encodeURIComponent(
              JSON.stringify(options[fields[i]].toGeoJSON())
            )}`
            url += str
            break
          case 'FeatureCollection':
            url += `&${fields[i]}=${encodeURIComponent(
              JSON.stringify(options[fields[i]])
            )}`
            break
          default:
            url += `&${fields[i]}=${encodeURIComponent(_filter)}`
        }
      } else if (typeof checkOptions[fields[i]].process === 'string') {
        // 有定义好的处理类型
        switch (checkOptions[fields[i]].process) {
          case 'igsGeometryServer':
            url += `&${fields[i]}=${encodeURIComponent(
              JSON.stringify(_filter.toGeoJSON())
            )}&srs=`
            // 确保spatialReference存在
            if (_filter.spatialReference) {
              // 是SpatialReference对象
              if (_filter.spatialReference instanceof SpatialReference) {
                url += encodeURIComponent(_filter.spatialReference.toString())
              } else if (
                _filter.spatialReference instanceof Object &&
                !(_filter.spatialReference instanceof Array)
              ) {
                // 外部传入一个对象
                url += encodeURIComponent(
                  _filter.spatialReference.wkt
                    ? _filter.spatialReference.wkt
                    : 'EPSG:4326'
                )
              } else if (typeof _filter.spatialReference === 'string') {
                // 传入字符串
                url += encodeURIComponent(_filter.spatialReference)
              }
            } else {
              // spatialReference不存在,默认EPSG:4326
              url += encodeURIComponent('EPSG:4326')
            }
            break
          case 'igsGeometryServerNoSRS':
            url += `&${fields[i]}=${encodeURIComponent(
              JSON.stringify(_filter.toGeoJSON())
            )}`
            break
          case 'igsRange$':
            url += `&${
              checkOptions[fields[i]].alias || fields[i]
            }=${encodeURIComponent(_filter.toIGSOldString())}`
            break
          case 'igsGeometryOld':
            if (_filter.type === 'Point' || _filter.type === 'LineString') {
              if (_filter.type === 'Point' && _filter.hasZ === true) {
                url += `&${fields[i]}=${encodeURIComponent(
                  `${_filter.toString()},${
                    options['distance'] || checkOptions['distance'].default
                  }`
                )}&geometryType=${encodeURIComponent(_filter.getIGSType())}`
              } else {
                url += `&${fields[i]}=${encodeURIComponent(
                  `${_filter.toString()};${
                    options['distance'] || checkOptions['distance'].default
                  }`
                )}&geometryType=${encodeURIComponent(_filter.getIGSType())}`
              }
            } else {
              url += `&${fields[i]}=${encodeURIComponent(
                _filter.toString()
              )}&geometryType=${encodeURIComponent(_filter.getIGSType())}`
            }
            break
          default:
            url += `&${fields[i]}=${encodeURIComponent(
              _filter.toString()
            )}&geometryType=${encodeURIComponent(_filter.getIGSType())}`
        }
      } else if (checkOptions[fields[i]].process instanceof Function) {
        // 方法类型
        url += checkOptions[fields[i]].process(
          options[fields[i]],
          checkOptions[fields[i]].default
        )
      }
    }
  }

  return url
}

function getParametersObject(fields, options, checkOptions) {
  const data = {}
  for (let i = 0; i < fields.length; i++) {
    // 获取查询条件
    const _filter = defaultValue(
      options[fields[i]],
      checkOptions[fields[i]].default
    )
    // 必须不为空
    if (_filter !== undefined) {
      // 没有process参数,走类型判断
      if (isNull(checkOptions[fields[i]].process)) {
        // 根据类型进行数据处理
        switch (checkOptions[fields[i]].type) {
          case 'String':
          case 'Number':
          case 'Boolean':
          default:
            data[checkOptions[fields[i]].alias || fields[i]] = _filter
            break
          case 'Geometry':
          case 'Point':
          case 'MultiPoint':
          case 'Extent':
          case 'Circle':
          case 'LineString':
          case 'MultiLineString':
          case 'Polygon':
          case 'MultiPolygon':
            data[
              checkOptions[fields[i]].alias || fields[i]
            ] = `${_filter.toString()}&geometryType=${_filter.getIGSType()}`
            break
        }
      } else if (typeof checkOptions[fields[i]].process === 'string') {
        // 有定义好的处理类型
        switch (checkOptions[fields[i]].process) {
          case 'igsDots':
            data[checkOptions[fields[i]].alias || 'Dots'] = _filter.toDots()
            break
          case 'toOldIGSGeometry':
            switch (_filter.type) {
              case 'Point':
                data[checkOptions[fields[i]].alias || 'Pnt'] =
                  _filter.toOldIGSGeometry().PntGeom[0]
                break
              case 'LineString':
                data[checkOptions[fields[i]].alias || 'Line'] =
                  _filter.toOldIGSGeometry().LinGeom[0]
                break
              case 'Polygon':
                data[checkOptions[fields[i]].alias || 'Reg'] =
                  _filter.toOldIGSGeometry().RegGeom[0]
                break
              default:
            }
            break
          default:
            data[checkOptions[fields[i]].alias || fields[i]] = _filter
        }
      } else if (checkOptions[fields[i]].process instanceof Function) {
        // 方法类型
        data[fields[i]] = checkOptions[fields[i]].process(
          options[fields[i]],
          checkOptions[fields[i]].default
        )
      }
    }
  }

  return encodeURIComponent(JSON.stringify(data))
}

/**
 * 检测输入参数类型是否是OutStatistics
 * @private
 * @param {OutStatistics} param 输入参数
 * @return {Boolean} 是否是正确的类型
 * */
function isOutStatistics(param) {
  // 首先必须是数组
  if (!(param instanceof Array)) {
    return false
  }

  // 循环所有子元素
  for (let i = 0; i < param.length; i++) {
    // 子元素一定是对象
    if (!(param[i] instanceof Object)) {
      return false
    }

    // 子元素不可以是数组
    if (param[i] instanceof Object && param[i] instanceof Array) {
      return false
    }

    // 子元素必须包含statisticType、onStatisticField以及outStatisticFieldName
    if (
      !param[i].hasOwnProperty('statisticType') ||
      !param[i].hasOwnProperty('onStatisticField') ||
      !param[i].hasOwnProperty('outStatisticFieldName')
    ) {
      return false
    }

    // 子元素的statisticType、onStatisticField以及outStatisticFieldName必须不为空
    if (
      isNull(param[i]['statisticType']) ||
      isNull(param[i]['onStatisticField']) ||
      isNull(param[i]['outStatisticFieldName'])
    ) {
      return false
    }

    // 子元素的statisticType、onStatisticField以及outStatisticFieldName必须为String类型
    if (
      !isString(param[i]['statisticType']) ||
      !isString(param[i]['onStatisticField']) ||
      !isString(param[i]['outStatisticFieldName'])
    ) {
      return false
    }
  }

  return true
}

/**
 * 检测输入参数类型是否正确
 * @private
 * @param {String} type 输入参数类型
 * @param {Any} param 输入参数
 * @return {Boolean} 是否是正确的类型
 * */
function checkType(type, param) {
  if (typeof type === 'function') {
    return type(param)
  }
  let flag
  switch (type) {
    case 'String':
      flag = isString(param)
      break
    case 'Number':
      flag = isNumber(param)
      break
    case 'Boolean':
      flag = isBoolean(param)
      break
    case 'Extent':
      flag = param instanceof Extent
      break
    case 'Geometry':
      flag = param instanceof Geometry
      break
    case 'Point':
      flag = param instanceof Point
      break
    case 'Polygon':
      flag = param instanceof Polygon
      break
    case 'MultiPolygon':
      flag = param instanceof MultiPolygon
      break
    case 'Circle':
      flag = param instanceof Circle
      break
    case 'LineString':
      flag = param instanceof LineString
      break
    case 'MultiLineString':
      flag = param instanceof MultiLineString
      break
    case 'LineString | MultiLineString':
      flag = param instanceof LineString || param instanceof MultiLineString
      break
    case 'Polygon | Extent':
      flag = param instanceof Polygon || param instanceof Extent
      break
    case 'Array':
      flag = param instanceof Array
      break
    case 'Object':
      flag = param instanceof Object
      break
    case 'OutStatistics':
      flag = isOutStatistics(param)
      break
    case 'FeatureSet':
      flag = param instanceof FeatureSet
      break
    case 'FeatureCollection':
      flag =
        param instanceof Object &&
        !(param instanceof Array) &&
        param.hasOwnProperty('features') &&
        param.type === 'FeatureCollection'
      break
    case 'Color':
      flag = param instanceof Color
      break
    default:
      flag = isString(param)
  }

  return flag
}

/**
 * 检测输入参数正确性
 * @private
 * @param {Object} options 输入参数
 * @param {Object} checkOptions 检测规则
 * */
function checkParam(options, checkOptions) {
  // 是否检测通过
  let isChecked = true
  // 错误信息
  let errorMessage = ''
  // 错误类型
  let errorType = ''
  // 错误变量名
  let wrongKey
  // 请求参数
  let queryString = ''

  // 不通过检测不走下面的逻辑
  try {
    // 检测类型
    let flag = true
    Object.keys(checkOptions).forEach(function (key) {
      if (
        (options.hasOwnProperty(key) && checkOptions.hasOwnProperty(key)) ||
        (checkOptions.hasOwnProperty(key) && checkOptions[key].required)
      ) {
        // 检测空输入
        if (checkOptions[key].required) {
          // 不是多选一
          if (isNull(checkOptions[key].oneOf)) {
            if (isNull(options[key])) {
              wrongKey = key
              throw new Error('isNull')
            }
          } // 是多选一,如果都为空,才报错
          else {
            // 是否都为空
            let allIsNull = false

            // 确定本身是否为空
            if (isNull(options[key])) {
              allIsNull = true
            }

            // 确定其他的可选参数是否为空
            for (let i = 0; i < checkOptions[key].oneOf.length; i++) {
              if (!isNull(options[checkOptions[key].oneOf[i]])) {
                allIsNull = false
                break
              }
            }

            // 如果都为空,报错
            if (allIsNull) {
              wrongKey = `${key},${checkOptions[key].oneOf.toString()}`
              throw new Error('isNull')
            }
          }
        }

        // 由于上面做了多选一的判断,这里进行下非空判断
        if (!isNull(options[key])) {
          flag = checkType(checkOptions[key].type, options[key])
        }

        if (!flag) {
          wrongKey = key
          throw new Error('wrongType')
        }
      }
    })

    if (flag) {
      const fields = []
      Object.keys(checkOptions).forEach((key) => {
        if (checkOptions.hasOwnProperty(key)) {
          fields.push(key)
        }
      })
      if (options.useObject) {
        queryString = getParametersObject(fields, options, checkOptions)
      } else {
        queryString = getParameters(fields, options, checkOptions)
      }
    }
  } catch (e) {
    isChecked = false
    switch (e.message) {
      case 'isNull':
        errorMessage = `${wrongKey}值不能为空!`
        errorType = 'isNull'
        Log.error(errorMessage)
        break
      case 'wrongType':
        errorMessage = `${wrongKey}类型错误!`
        errorType = 'isWrongType'
        Log.error(errorMessage)
        break
      default:
        errorMessage = `${wrongKey}值不能为空!`
        errorType = 'isNull'
        Log.error(errorMessage)
    }
  }

  return {
    isChecked,
    errorMessage,
    errorType,
    queryString
  }
}

/**
 * 验证所有PathParameter参数的正确性,PathParameter里的参数都是必填参数,必须验证正确性
 * @private
 * @param {Object} checkOptions 验证对象
 * @param {Object} options 请求参数对象
 * @return {Object} 是否验证通过对象
 * */
function checkPathParameters(checkOptions, options) {
  let errorType = ''
  let errorMessage = ''
  let isChecked = true

  // try&catch是为了跳出forEach的循环
  try {
    Object.keys(checkOptions).forEach((key) => {
      // 要检测某个参数
      if (checkOptions.hasOwnProperty(key)) {
        // 有这个参数的值
        if (options.hasOwnProperty(key)) {
          const param = options[key]

          // 非空判断
          if (isNull(param)) {
            errorType = 'isNull'
            isChecked = false
            throw new Error(`${key}不能为空!`)
          }

          // 类型判断
          if (!checkType(checkOptions[key].type, options[key])) {
            errorType = 'isWrongType'
            isChecked = false
            throw new Error(`${key}类型错误!`)
          }
        } else {
          // 没有这个参数的值
          errorType = 'isNull'
          isChecked = false
          throw new Error(`${key}不能为空!`)
        }
      }
    })
  } catch (e) {
    Log.error(e)
    errorMessage = e
    return {
      isChecked,
      errorMessage,
      errorType
    }
  }

  return {
    isChecked,
    errorMessage,
    errorType
  }
}

/**
 * 获取XML的DOM对象
 * @param xml xml字符串对象
 * @return string
 */
function getDoc(xml) {
  let xmlDoc = null
  if (window.DOMParser) {
    const parser = new DOMParser()
    xmlDoc = parser.parseFromString(xml, 'text/xml')
  } else {
    // IE
    // eslint-disable-next-line no-undef
    xmlDoc = new ActiveXObject('Microsoft.XMLDOM')
    xmlDoc.async = 'false'
    xmlDoc.loadXML(xml)
  }

  return xmlDoc
}

/**
 * 从DOM元素中获取信息
 * @param dom dom元素
 * @param WMSInfo WMS信息对象
 */
function getWMSInfoFromDOM(dom, WMSInfo) {
  // 取得整个图层的Title信息
  if (dom.nodeName === 'Name') {
    WMSInfo.name = dom.innerHTML
  } else if (dom.nodeName === 'Abstract') {
    // WMS的1.1.1版本信息
    WMSInfo.abstract = dom.innerHTML
  } else if (dom.nodeName === 'Title') {
    let title = dom.innerHTML
    // 注意排除文件夹名
    if (title.indexOf(':') > -1) {
      title = title.split(':')[1]
    }
    WMSInfo.title = title
  } else if (dom.nodeName === 'SRS') {
    // 取得整个图层的SRS信息
    WMSInfo.srs.push(dom.innerHTML)
  } else if (dom.nodeName === 'CRS') {
    // 取得整个图层的CRS信息
    WMSInfo.crs.push(dom.innerHTML)
  } else if (dom.nodeName === 'BoundingBox') {
    // 取得整个图层的BoundingBox信息
    let boundingBox = {}
    // WMS 1.1.1版本是SRS
    if (dom.attributes.SRS) {
      boundingBox = {
        minx: dom.attributes.minx.value,
        miny: dom.attributes.miny.value,
        maxx: dom.attributes.maxx.value,
        maxy: dom.attributes.maxy.value
      }
      boundingBox.srs = dom.attributes.SRS.value
    } else if (dom.attributes.CRS) {
      const EPSG = dom.attributes.CRS.value
      const epsgNo = Number(EPSG.split(':')[1])
      // 高斯坐标系,xy反转
      if (
        (epsgNo >= 2327 && epsgNo <= 2442) ||
        (epsgNo >= 4491 && epsgNo <= 4554) ||
        (epsgNo >= 21413 && epsgNo <= 21423) ||
        (epsgNo >= 21473 && epsgNo <= 21483)
      ) {
        boundingBox = {
          minx: dom.attributes.miny.value,
          miny: dom.attributes.minx.value,
          maxx: dom.attributes.maxy.value,
          maxy: dom.attributes.maxx.value
        }
      }
      // 经纬度,xy反转
      else if (
        epsgNo === 4326 ||
        epsgNo === 4214 ||
        epsgNo === 4490 ||
        epsgNo === 4610
      ) {
        boundingBox = {
          minx: dom.attributes.miny.value,
          miny: dom.attributes.minx.value,
          maxx: dom.attributes.maxy.value,
          maxy: dom.attributes.maxx.value
        }
      }
      // 其他xy正常
      else {
        boundingBox = {
          minx: dom.attributes.minx.value,
          miny: dom.attributes.miny.value,
          maxx: dom.attributes.maxx.value,
          maxy: dom.attributes.maxy.value
        }
      }
      // WMS 1.3.0版本是CRS
      boundingBox.crs = dom.attributes.CRS.value
    }
    WMSInfo.boundingBox.push(boundingBox)
  } else if (dom.nodeName === 'LatLonBoundingBox') {
    // WMS的1.1.1版本信息
    WMSInfo.latLonBoundingBox = {
      minx: dom.attributes.miny.value,
      miny: dom.attributes.minx.value,
      maxx: dom.attributes.maxy.value,
      maxy: dom.attributes.maxx.value
    }
  } else if (dom.nodeName === 'EX_GeographicBoundingBox') {
    // WMS的1.3.0版本信息
    WMSInfo.geographicBoundingBox = {
      westBoundLongitude: dom.childNodes[0].innerHTML,
      eastBoundLongitude: dom.childNodes[1].innerHTML,
      southBoundLatitude: dom.childNodes[2].innerHTML,
      northBoundLatitude: dom.childNodes[3].innerHTML
    }
  }
}

/**
 * 将XML的Document对象转换为JSON字符串
 * @param xmlDoc xml的Document对象
 * @param version WMS版本
 * @return {Object} WMS的元数据信息
 */
function getWMSInfoFromXML(xmlDoc, version) {
  const WMSInfo = {
    boundingBox: [],
    layer: []
  }

  if (version === '1.3.0') {
    WMSInfo.crs = []
  } else {
    WMSInfo.srs = []
  }

  // 获取xml文档的所有子节点
  const nodeList = xmlDoc.childNodes

  for (let i = 0; i < nodeList.length; i++) {
    // 取得localName为WMT_MS_Capabilities的子元素,注意一定是localName
    if (
      nodeList[i].nodeName === 'WMT_MS_Capabilities' ||
      nodeList[i].nodeName === 'WMS_Capabilities'
    ) {
      const childNodes = nodeList[i].childNodes
      for (let j = 0; j < childNodes.length; j++) {
        // 只取nodeName为Capability的子元素
        if (childNodes[j].nodeName === 'Capability') {
          const cbChildren = childNodes[j].childNodes
          for (let k = 0; k < cbChildren.length; k++) {
            // 取Capability里面名字为Layer的子元素
            if (cbChildren[k].nodeName === 'Layer') {
              const layerChildren = cbChildren[k].childNodes
              // 取得整个图层的WMS信息
              for (let m = 0; m < layerChildren.length; m++) {
                // 取得所有Layer信息
                if (layerChildren[m].nodeName === 'Layer') {
                  const layerInfos = layerChildren[m].childNodes
                  const layerInfo = {
                    boundingBox: []
                  }
                  if (version === '1.3.0') {
                    layerInfo.crs = []
                  } else {
                    layerInfo.srs = []
                  }
                  for (let n = 0; n < layerInfos.length; n++) {
                    // 取得单个图层的WMS信息
                    getWMSInfoFromDOM(layerInfos[n], layerInfo)
                  }
                  WMSInfo.layer.push(layerInfo)
                } else {
                  // 取得其他信息
                  getWMSInfoFromDOM(layerChildren[m], WMSInfo)
                }
              }
              break
            }
          }
          break
        }
      }
      break
    }
  }

  return WMSInfo
}

/**
 * 将XML的Document对象转换为JSON字符串
 * @param xmlDoc xml的Document对象
 * @return {Object} WMTS的元数据信息
 */
function getWMTSInfoFromXML(xmlDoc) {
  const rootChildren = xmlDoc.childNodes
  const WMTSInfo = {
    layer: {
      infoFormat: [],
      tileMatrixSetLink: []
    },
    tileMatrixSet: []
  }

  for (let i = 0; i < rootChildren.length; i++) {
    // 仅取Capabilities上的信息
    if (rootChildren[i].nodeName === 'Capabilities') {
      const cbChildren = rootChildren[i].childNodes
      for (let j = 0; j < cbChildren.length; j++) {
        // 仅取Contents上的信息
        if (cbChildren[j].nodeName === 'Contents') {
          const ctChildren = cbChildren[j].childNodes
          for (let k = 0; k < ctChildren.length; k++) {
            // 获取Layer上的信息
            if (ctChildren[k].nodeName === 'Layer') {
              const layerInfos = ctChildren[k].childNodes
              for (let x = 0; x < layerInfos.length; x++) {
                if (layerInfos[x].nodeName === 'ows:Title') {
                  WMTSInfo.layer.title = layerInfos[x].innerHTML
                } else if (layerInfos[x].nodeName === 'ows:Identifier') {
                  WMTSInfo.layer.identifier = layerInfos[x].innerHTML
                } else if (layerInfos[x].nodeName === 'ows:BoundingBox') {
                  const boundingBox = {}
                  for (let l = 0; l < layerInfos[x].childNodes.length; l++) {
                    if (
                      layerInfos[x].childNodes[l].nodeName === 'ows:LowerCorner'
                    ) {
                      boundingBox.lowerCorner =
                        layerInfos[x].childNodes[l].innerHTML
                    }
                    if (
                      layerInfos[x].childNodes[l].nodeName === 'ows:UpperCorner'
                    ) {
                      boundingBox.upperCorner =
                        layerInfos[x].childNodes[l].innerHTML
                    }
                  }
                  WMTSInfo.layer.boundingBox = boundingBox
                } else if (layerInfos[x].nodeName === 'ows:WGS84BoundingBox') {
                  WMTSInfo.layer.WGS84BoundingBox = {
                    lowerCorner: layerInfos[x].childNodes[0].innerHTML,
                    upperCorner: layerInfos[x].childNodes[1].innerHTML
                  }
                } else if (layerInfos[x].nodeName === 'Style') {
                  const Style = {}
                  for (let l = 0; l < layerInfos[x].childNodes.length; l++) {
                    if (
                      layerInfos[x].childNodes[l].nodeName === 'ows:Identifier'
                    ) {
                      Style.identifier = layerInfos[x].childNodes[l].innerHTML
                    }
                    if (layerInfos[x].childNodes[l].nodeName === 'ows:Title') {
                      Style.title = layerInfos[x].childNodes[l].innerHTML
                    }
                  }
                  WMTSInfo.layer.Style = Style
                } else if (layerInfos[x].nodeName === 'Format') {
                  WMTSInfo.layer.format = layerInfos[x].innerHTML
                } else if (layerInfos[x].nodeName === 'InfoFormat') {
                  WMTSInfo.layer.infoFormat.push(layerInfos[x].innerHTML)
                } else if (layerInfos[x].nodeName === 'TileMatrixSetLink') {
                  const links = layerInfos[x].childNodes
                  const TileMatrixSetLink = {
                    tileMatrixSetLimits: []
                  }

                  for (let w = 0; w < links.length; w++) {
                    if (links[w].nodeName === 'TileMatrixSet') {
                      TileMatrixSetLink.tileMatrixSet = links[w].innerHTML
                    } else if (links[w].nodeName === 'TileMatrixSetLimits') {
                      const limits = links[w].childNodes

                      for (let y = 0; y < limits.length; y++) {
                        const tls = limits[y].childNodes
                        const TileMatrixLimits = {}

                        for (let z = 0; z < tls.length; z++) {
                          if (tls[z].nodeName === 'TileMatrix') {
                            TileMatrixLimits.tileMatrix = tls[z].innerHTML
                          } else if (tls[z].nodeName === 'MinTileRow') {
                            TileMatrixLimits.minTileRow = tls[z].innerHTML
                          } else if (tls[z].nodeName === 'MaxTileRow') {
                            TileMatrixLimits.maxTileRow = tls[z].innerHTML
                          } else if (tls[z].nodeName === 'MinTileCol') {
                            TileMatrixLimits.minTileCol = tls[z].innerHTML
                          } else if (tls[z].nodeName === 'MaxTileCol') {
                            TileMatrixLimits.maxTileCol = tls[z].innerHTML
                          }
                        }

                        TileMatrixSetLink.tileMatrixSetLimits.push(
                          TileMatrixLimits
                        )
                      }
                    }
                  }

                  WMTSInfo.layer.tileMatrixSetLink.push(TileMatrixSetLink)
                }
              }
            } else if (ctChildren[k].nodeName === 'TileMatrixSet') {
              // 获取TileMatrixSet上的信息
              const TileMatrixSet = ctChildren[k].childNodes
              const tileMatrixSet = {
                tileMatrix: []
              }

              for (let m = 0; m < TileMatrixSet.length; m++) {
                if (TileMatrixSet[m].nodeName === 'ows:Title') {
                  tileMatrixSet.title = TileMatrixSet[m].innerHTML
                } else if (TileMatrixSet[m].nodeName === 'ows:Abstract') {
                  tileMatrixSet.abstract = TileMatrixSet[m].innerHTML
                } else if (TileMatrixSet[m].nodeName === 'ows:Identifier') {
                  tileMatrixSet.identifier = TileMatrixSet[m].innerHTML
                } else if (TileMatrixSet[m].nodeName === 'ows:SupportedCRS') {
                  tileMatrixSet.supportedCRS = TileMatrixSet[m].innerHTML
                } else if (TileMatrixSet[m].nodeName === 'TileMatrix') {
                  const TileMatrix = TileMatrixSet[m].childNodes
                  const tileMatrix = {}

                  for (let n = 0; n < TileMatrix.length; n++) {
                    if (TileMatrix[n].nodeName === 'ows:Identifier') {
                      tileMatrix.identifier = TileMatrix[n].innerHTML
                    } else if (TileMatrix[n].nodeName === 'ScaleDenominator') {
                      tileMatrix.scaleDenominator = TileMatrix[n].innerHTML
                    } else if (TileMatrix[n].nodeName === 'TopLeftCorner') {
                      tileMatrix.topLeftCorner = TileMatrix[n].innerHTML
                    } else if (TileMatrix[n].nodeName === 'TileWidth') {
                      tileMatrix.tileWidth = TileMatrix[n].innerHTML
                    } else if (TileMatrix[n].nodeName === 'TileHeight') {
                      tileMatrix.tileHeight = TileMatrix[n].innerHTML
                    } else if (TileMatrix[n].nodeName === 'MatrixWidth') {
                      tileMatrix.matrixWidth = TileMatrix[n].innerHTML
                    } else if (TileMatrix[n].nodeName === 'MatrixHeight') {
                      tileMatrix.matrixHeight = TileMatrix[n].innerHTML
                    }
                  }

                  tileMatrixSet.tileMatrix.push(tileMatrix)
                }
              }

              WMTSInfo.tileMatrixSet.push(tileMatrixSet)
            }
          }
          break
        }
      }
      break
    }
  }

  return WMTSInfo
}

/**
 * 将XML的Document对象转换为JSON字符串
 * @param xmlDoc xml的Document对象
 * @return {Object} WFS的元数据信息
 */
function getWFSInfoFromXML(xmlDoc) {
  const rootChildren = xmlDoc.childNodes
  const WFSInfo = {
    featureTypeList: []
  }

  // 循环子元素
  for (let i = 0; i < rootChildren.length; i++) {
    if (rootChildren[i].nodeName === 'wfs:WFS_Capabilities') {
      const cpChildren = rootChildren[i].childNodes
      for (let m = 0; m < cpChildren.length; m++) {
        // 只拿FeatureTypeList里的数据
        if (cpChildren[m].nodeName === 'FeatureTypeList') {
          const ftList = cpChildren[m].childNodes
          for (let j = 0; j < ftList.length; j++) {
            // 只拿FeatureType里的数据
            if (ftList[j].nodeName === 'FeatureType') {
              const featureType = {}
              const ftChildren = ftList[j].childNodes
              for (let k = 0; k < ftChildren.length; k++) {
                if (ftChildren[k].nodeName.toLowerCase() === 'name') {
                  featureType.name = ftChildren[k].innerHTML
                } else if (ftChildren[k].nodeName.toLowerCase() === 'title') {
                  featureType.title = ftChildren[k].innerHTML
                } else if (
                  ftChildren[k].nodeName.toLowerCase() === 'abstract'
                ) {
                  featureType.abstract = ftChildren[k].innerHTML
                } else if (
                  ftChildren[k].nodeName.toLowerCase() === 'defaultsrs'
                ) {
                  featureType.defaultSRS = ftChildren[k].innerHTML
                } else if (
                  ftChildren[k].nodeName.toLowerCase() ===
                  'ows:wgs84boundingbox'
                ) {
                  featureType.WGS84BoundingBox = {
                    lowerCorner: ftChildren[k].childNodes[0].innerHTML,
                    UpperCorner: ftChildren[k].childNodes[1].innerHTML
                  }
                }
              }
              WFSInfo.featureTypeList.push(featureType)
            }
          }
          break
        }
      }
    }
  }

  return WFSInfo
}

function parseWFSElementForSpatialReference(element) {
  let srsName = 'EPSG:4326'
  if (!element) {
    return srsName
  }
  const _srsName = element.getAttribute('srsName')
  if (!_srsName) return srsName
  const res = _srsName.match(/EPSG::\d+/)
  if (res[0]) {
    srsName = `EPSG:${res[0].replace('EPSG::', '')}`
  }
  return srsName
}

function getWFSFeature(xmlDoc) {
  const rootChildren = xmlDoc.childNodes
  const WFSFeatureDom = rootChildren[0].childNodes
  const WFSFeature = new FeatureSet()

  for (let i = 0; i < WFSFeatureDom.length; i++) {
    const WFSSubLayer = WFSFeatureDom[i].childNodes[0]
    const WFSSubLayerChildren = WFSSubLayer.childNodes
    const attributes = {}
    let geometry = undefined
    for (let j = 0; j < WFSSubLayerChildren.length; j++) {
      // 多边形几何,确保节点名称包含:the_geom
      if (WFSSubLayerChildren[j].nodeName.indexOf(':the_geom') > -1) {
        // 遍历子节点,最后找到节点名包含exterior的节点,里面的就是多边形的点坐标
        const WFSGeometry = WFSSubLayerChildren[j]
        // 解析空间参考系
        const srsName = parseWFSElementForSpatialReference(
          WFSGeometry.childNodes[0]
        )
        WFSFeature.spatialReference = new SpatialReference(srsName)
        if (WFSGeometry.childNodes[0].nodeName.indexOf('MultiSurface') > -1) {
          const WFSMultiSurface = WFSGeometry.childNodes[0]
          const WFSSurfaceMembers = WFSMultiSurface.childNodes
          if (WFSSurfaceMembers.length === 1) {
            const WFSPolygon = WFSSurfaceMembers[0].childNodes[0]
            const WFSPolygonChildNodes = WFSPolygon.childNodes
            for (let k = 0; k < WFSPolygonChildNodes.length; k++) {
              if (WFSPolygonChildNodes[k].nodeName.indexOf('exterior') > -1) {
                const WFSPolygonExterior = WFSPolygonChildNodes[k]
                const WFSPolygonExteriorPoints =
                  WFSPolygonExterior.childNodes[0].childNodes[0].innerHTML.split(
                    ' '
                  )
                const exteriorPoints = []
                for (let l = 0; l < WFSPolygonExteriorPoints.length; l += 2) {
                  exteriorPoints.push([
                    Number(WFSPolygonExteriorPoints[l]),
                    Number(WFSPolygonExteriorPoints[l + 1])
                  ])
                }
                geometry = new Polygon({
                  coordinates: [exteriorPoints]
                })
              }
            }
          } else if (WFSSurfaceMembers.length > 1) {
            // 未测试该情况,要向igs了解
          }
        }
        // 线几何,确保节点名称包含MultiCurve
        else if (
          WFSGeometry.childNodes[0].nodeName.indexOf('MultiCurve') > -1
        ) {
          // 遍历子节点,最后找到节点名包含posList的节点,里面的就是线的点坐标
          const WFSMultiSurface = WFSGeometry.childNodes[0]
          const WFSSurfaceMembers = WFSMultiSurface.childNodes
          if (WFSSurfaceMembers.length === 1) {
            const WFSLine = WFSSurfaceMembers[0].childNodes[0]
            const WFSLineChildNodes = WFSLine.childNodes
            for (let k = 0; k < WFSLineChildNodes.length; k++) {
              if (WFSLineChildNodes[k].nodeName.indexOf('posList') > -1) {
                const WFSLineString = WFSLineChildNodes[k]
                const WFSLineStringPoints = WFSLineString.innerHTML.split(' ')
                const lineStringPoints = []
                for (let l = 0; l < WFSLineStringPoints.length; l += 2) {
                  lineStringPoints.push([
                    Number(WFSLineStringPoints[l]),
                    Number(WFSLineStringPoints[l + 1])
                  ])
                }
                geometry = new LineString({
                  coordinates: lineStringPoints
                })
              }
            }
          } else if (WFSSurfaceMembers.length > 1) {
            // 未测试该情况,要向igs了解
          }
        }
        // 点几何,确保节点名称包含MultiCurve
        else if (
          WFSGeometry.childNodes[0].nodeName.indexOf('MultiPoint') > -1
        ) {
          // 遍历子节点,最后找到节点名包含posList的节点,里面的就是线的点坐标
          const WFSMultiPoint = WFSGeometry.childNodes[0]
          const WFSPointMembers = WFSMultiPoint.childNodes
          if (WFSPointMembers.length === 1) {
            const WFSPoint = WFSPointMembers[0].childNodes[0]
            const WFSPointPos = WFSPoint.childNodes[0].innerHTML.split(' ')
            geometry = new Point({
              coordinates: [Number(WFSPointPos[0]), Number(WFSPointPos[1])]
            })
          } else if (WFSPointMembers.length > 1) {
            // 未测试该情况,要向igs了解
          }
        }
      }
      // 属性信息
      else {
        let key = WFSSubLayerChildren[j].nodeName
        key = key.split(':')[1]
        attributes[key] = WFSSubLayerChildren[j].innerHTML
      }
    }
    const feature = new Feature({
      geometry,
      attributes
    })
    WFSFeature.features.push(feature)
  }

  return WFSFeature
}

function fromQueryResult(result) {
  function _fromQueryResult(result) {
    if (
      !result.hasOwnProperty('SFEleArray') ||
      !result.hasOwnProperty('AttStruct') ||
      (result.hasOwnProperty('SFEleArray') && !result.SFEleArray) ||
      (result.hasOwnProperty('AttStruct') && !result.AttStruct)
    ) {
      return []
    }
    const SFEleArray = result.SFEleArray
    const AttStruct = result.AttStruct
    const featureSet = new FeatureSet({
      spatialReference: new SpatialReference('EPSG:0000')
    })
    let feature
    let geometry
    let coordinates
    for (let i = 0; i < SFEleArray.length; i++) {
      const attributes = {}
      for (let j = 0; j < SFEleArray[i].AttValue.length; j++) {
        if (SFEleArray[i].AttValue[j] !== '') {
          attributes[AttStruct.FldName[j]] = SFEleArray[i].AttValue[j]
        }
      }
      if (SFEleArray[i].fGeom) {
        switch (SFEleArray[i].ftype) {
          case 1:
            // 多个点
            const PntGeom = SFEleArray[i].fGeom.PntGeom
            // 获取所有点的点坐标
            coordinates = []
            for (let k = 0; k < PntGeom.length; k++) {
              // 处理数据
              const dot = PntGeom[k].Dot
              coordinates.push([dot.x, dot.y])
            }
            geometry = new MultiPoint({
              coordinates
            })
            break
          case 2:
            // 多个线
            const LinGeom = SFEleArray[i].fGeom.LinGeom
            // 获取所有线的点坐标
            coordinates = []
            for (let k = 0; k < LinGeom.length; k++) {
              // 处理下数据
              const dots = LinGeom[k].Line.Arcs[0].Dots
              const lineCos = []
              for (let i = 0; i < dots.length; i++) {
                lineCos.push([dots[i].x, dots[i].y])
              }
              coordinates.push(lineCos)
            }
            geometry = new MultiLineString({
              coordinates
            })
            break
          case 3:
          default:
            // 多个多边形
            const RegGeom = SFEleArray[i].fGeom.RegGeom
            // 获取所有多边形的点坐标
            coordinates = []
            for (let k = 0; k < RegGeom.length; k++) {
              // 这个是多边形的外圈
              const outerDots = RegGeom[k].Rings[0].Arcs[0].Dots
              // 处理下数据
              const outerCos = []
              for (let i = 0; i < outerDots.length; i++) {
                outerCos.push([outerDots[i].x, outerDots[i].y])
              }
              const singleCoordinates = [outerCos]
              for (let m = 1; m < RegGeom[k].Rings.length; m++) {
                // 这个是多边形的内圈
                // 处理数据
                const innerDots = RegGeom[k].Rings[m].Arcs[0].Dots
                const innerCos = []
                for (let i = 0; i < innerDots.length; i++) {
                  innerCos.push([innerDots[i].x, innerDots[i].y])
                }
                singleCoordinates.push(innerCos)
              }
              coordinates.push(singleCoordinates)
            }
            geometry = new MultiPolygon({
              coordinates
            })
            break
        }
      }
      let symbol
      if (SFEleArray[i].GraphicInfo) {
        const GraphicInfo = SFEleArray[i].GraphicInfo
        switch (GraphicInfo.InfoType) {
          case 1:
            symbol = GraphicInfo.PntInfo
            break
          case 2:
            symbol = GraphicInfo.LinInfo
            break
          case 3:
          default:
            symbol = GraphicInfo.RegInfo
            break
        }
      }

      feature = new Feature({
        id: SFEleArray[i].FID,
        attributes,
        geometry,
        symbol
      })
      featureSet.features.push(feature)
    }
    return featureSet
  }

  if (result instanceof Array) {
    const featureSets = []
    for (let i = 0; i < result.length; i++) {
      featureSets.push(_fromQueryResult(result[i]))
    }
    return featureSets
  } else {
    return [_fromQueryResult(result)]
  }
}

function formatBaseUrl(url) {
  const _index = url.indexOf('?')
  if (_index < 0) {
    return {
      baseUrl: url,
      params: {}
    }
  }
  const _baseUrl = url.substring(0, _index)
  const _paramStr = url.substring(_index + 1, url.length)
  return {
    baseUrl: _baseUrl,
    paramString: _paramStr ? `&${_paramStr}` : ''
  }
}

function ServiceConfigToken(Config) {
  let tokenStr = ''
  if (Config) {
    if (Config.tokenKey && Config.tokenValue) {
      tokenStr = `${Config.tokenKey}=${Config.tokenValue}`
    }
  }
  return tokenStr
}

function ServiceConfigRequestInterceptors(Config, url) {
  url = defaultValue(url, '')
  const requestInterceptors = Config.request.interceptors
  const _urlOrigin = decodeURI(url)
  if (requestInterceptors && requestInterceptors instanceof Array) {
    let _beforeUrl = ''
    for (let i = 0; i < requestInterceptors.length; i++) {
      const urls = requestInterceptors[i].urls
      const before = requestInterceptors[i].before
      // 不存在urls,则应用到全部url上
      if (!urls) {
        if (before && before instanceof Function) {
          const _before = before(url)
          if (_before) {
            _beforeUrl += _before
          }
        }
      }
      // urls是字符串
      else if (typeof urls === 'string') {
        const _url = decodeURI(urls)
        if (_urlOrigin.indexOf(_url) > -1) {
          if (before && before instanceof Function) {
            const _before = before(url)
            if (_before) {
              _beforeUrl += _before
            }
          }
        }
      }
      // urls是数组
      else if (urls instanceof Array) {
        for (let j = 0; j < urls.length; j++) {
          const _url = decodeURI(urls[j])
          if (_urlOrigin.indexOf(_url) > -1) {
            if (before && before instanceof Function) {
              const _before = before(url)
              if (_before) {
                _beforeUrl += _before
              }
            }
          }
        }
      }
      if (_beforeUrl) {
        url = _beforeUrl
      }
    }
  }
  return url
}

function ServiceConfigResponseInterceptors(Config, url, response) {
  url = defaultValue(url, '')
  const requestInterceptors = Config.request.interceptors
  const _urlOrigin = decodeURI(url)
  if (requestInterceptors && requestInterceptors instanceof Array) {
    for (let i = 0; i < requestInterceptors.length; i++) {
      const urls = requestInterceptors[i].urls
      const after = requestInterceptors[i].after
      // 不存在urls,则应用到全部url上
      if (!urls || (urls instanceof Array && urls.length === 0)) {
        if (after && after instanceof Function) {
          const _after = after(response)
          if (_after) {
            return _after
          }
        }
      }
      // urls是字符串
      else if (typeof urls === 'string') {
        const _url = decodeURI(urls)
        if (_urlOrigin.indexOf(_url) > -1) {
          if (after && after instanceof Function) {
            const _after = after(response)
            if (_after) {
              return _after
            }
          }
        }
      }
      // urls是数组
      else if (urls instanceof Array) {
        for (let j = 0; j < urls.length; j++) {
          const _url = decodeURI(urls[j])
          if (_urlOrigin.indexOf(_url) > -1) {
            if (after && after instanceof Function) {
              const _after = after(response)
              if (_after) {
                return _after
              }
            }
          }
        }
      }
    }
  }
  return response
}

export {
  fromQueryResult,
  checkParam,
  getParameters,
  checkPathParameters,
  getWMSInfoFromXML,
  getDoc,
  getWMTSInfoFromXML,
  getWFSInfoFromXML,
  getParametersObject,
  getWFSFeature,
  formatBaseUrl,
  ServiceConfigToken,
  ServiceConfigRequestInterceptors,
  ServiceConfigResponseInterceptors
}
构造函数
成员变量
方法
事件