如何自己实现一个丝滑的流程图绘制工具(五)bpmn的xml和json互转

news/2024/5/18 23:53:37 标签: 流程图, xml, json
xmlns="http://www.w3.org/2000/svg" style="display: none;">

背景

因为服务端给的数据并不是xml,而且服务端要拿的数据是json,所以我们只能xmljson互转,来完成和服务端的对接

xmljson_3">xmljson
import XML from './config/jsonxml.js'

 /**
     * xml转为json
     * @param {*} xml
     */
    xmlToJson(xml) {
      const xotree = new XML.ObjTree()
      const jsonData = xotree.parseXML(xml)
      return jsonData
    },

jsonxml.js

const XML = function() {}

//  constructor

XML.ObjTree = function() {
  return this
}

//  class variables

XML.ObjTree.VERSION = '0.23'

//  object prototype

XML.ObjTree.prototype.xmlDecl = '<?xml version="1.0" encoding="UTF-8" ?>\n'
XML.ObjTree.prototype.attr_prefix = '-'

//  method: parseXML( xmlsource )

XML.ObjTree.prototype.parseXML = function(xml) {
  let root
  if (window.DOMParser) {
    var xmldom = new DOMParser()
    //      xmldom.async = false;           // DOMParser is always sync-mode
    const dom = xmldom.parseFromString(xml, 'application/xml')
    if (!dom) return
    root = dom.documentElement
  } else if (window.ActiveXObject) {
    xmldom = new ActiveXObject('Microsoft.XMLDOM')
    xmldom.async = false
    xmldom.loadXML(xml)
    root = xmldom.documentElement
  }
  if (!root) return
  return this.parseDOM(root)
}

//  method: parseHTTP( url, options, callback )

XML.ObjTree.prototype.parseHTTP = function(url, options, callback) {
  const myopt = {}
  for (const key in options) {
    myopt[key] = options[key] // copy object
  }
  if (!myopt.method) {
    if (
      typeof myopt.postBody === 'undefined' &&
      typeof myopt.postbody === 'undefined' &&
      typeof myopt.parameters === 'undefined'
    ) {
      myopt.method = 'get'
    } else {
      myopt.method = 'post'
    }
  }
  if (callback) {
    myopt.asynchronous = true // async-mode
    const __this = this
    const __func = callback
    const __save = myopt.onComplete
    myopt.onComplete = function(trans) {
      let tree
      if (trans && trans.responseXML && trans.responseXML.documentElement) {
        tree = __this.parseDOM(trans.responseXML.documentElement)
      }
      __func(tree, trans)
      if (__save) __save(trans)
    }
  } else {
    myopt.asynchronous = false // sync-mode
  }
  let trans
  if (typeof HTTP !== 'undefined' && HTTP.Request) {
    myopt.uri = url
    var req = new HTTP.Request(myopt) // JSAN
    if (req) trans = req.transport
  } else if (typeof Ajax !== 'undefined' && Ajax.Request) {
    var req = new Ajax.Request(url, myopt) // ptorotype.js
    if (req) trans = req.transport
  }
  if (callback) return trans
  if (trans && trans.responseXML && trans.responseXML.documentElement) {
    return this.parseDOM(trans.responseXML.documentElement)
  }
}

//  method: parseDOM( documentroot )

XML.ObjTree.prototype.parseDOM = function(root) {
  if (!root) return

  this.__force_array = {}
  if (this.force_array) {
    for (let i = 0; i < this.force_array.length; i++) {
      this.__force_array[this.force_array[i]] = 1
    }
  }

  let json = this.parseElement(root) // parse root node
  if (this.__force_array[root.nodeName]) {
    json = [json]
  }
  if (root.nodeType != 11) {
    // DOCUMENT_FRAGMENT_NODE
    const tmp = {}
    tmp[root.nodeName] = json // root nodeName
    json = tmp
  }
  return json
}

//  method: parseElement( element )

XML.ObjTree.prototype.parseElement = function(elem) {
  //  COMMENT_NODE
  if (elem.nodeType == 7) {
    return
  }

  //  TEXT_NODE CDATA_SECTION_NODE
  if (elem.nodeType == 3 || elem.nodeType == 4) {
    const bool = elem.nodeValue.match(/[^\x00-\x20]/)
    if (bool == null) return // ignore white spaces
    return elem.nodeValue
  }

  let retval
  const cnt = {}

  //  parse attributes
  if (elem.attributes && elem.attributes.length) {
    retval = {}
    for (var i = 0; i < elem.attributes.length; i++) {
      var key = elem.attributes[i].nodeName
      if (typeof key !== 'string') continue
      var val = elem.attributes[i].nodeValue
      if (!val) continue
      key = this.attr_prefix + key
      if (typeof cnt[key] === 'undefined') cnt[key] = 0
      cnt[key]++
      this.addNode(retval, key, cnt[key], val)
    }
  }

  //  parse child nodes (recursive)
  if (elem.childNodes && elem.childNodes.length) {
    let textonly = true
    if (retval) textonly = false // some attributes exists
    for (var i = 0; i < elem.childNodes.length && textonly; i++) {
      const ntype = elem.childNodes[i].nodeType
      if (ntype == 3 || ntype == 4) continue
      textonly = false
    }
    if (textonly) {
      if (!retval) retval = ''
      for (var i = 0; i < elem.childNodes.length; i++) {
        retval += elem.childNodes[i].nodeValue
      }
    } else {
      if (!retval) retval = {}
      for (var i = 0; i < elem.childNodes.length; i++) {
        var key = elem.childNodes[i].nodeName
        if (typeof key !== 'string') continue
        var val = this.parseElement(elem.childNodes[i])
        if (!val) continue
        if (typeof cnt[key] === 'undefined') cnt[key] = 0
        cnt[key]++
        this.addNode(retval, key, cnt[key], val)
      }
    }
  }
  return retval
}

//  method: addNode( hash, key, count, value )

XML.ObjTree.prototype.addNode = function(hash, key, cnts, val) {
  if (this.__force_array[key]) {
    if (cnts == 1) hash[key] = []
    hash[key][hash[key].length] = val // push
  } else if (cnts == 1) {
    // 1st sibling
    hash[key] = val
  } else if (cnts == 2) {
    // 2nd sibling
    hash[key] = [hash[key], val]
  } else {
    // 3rd sibling and more
    hash[key][hash[key].length] = val
  }
}

//  method: writeXML( tree )

XML.ObjTree.prototype.writeXML = function(tree) {
  const xml = this.hash_to_xml(null, tree)
  return this.xmlDecl + xml
}

//  method: hash_to_xml( tagName, tree )

XML.ObjTree.prototype.hash_to_xml = function(name, tree) {
  const elem = []
  const attr = []
  for (const key in tree) {
    if (!tree.hasOwnProperty(key)) continue
    const val = tree[key]
    if (key.charAt(0) != this.attr_prefix) {
      if (typeof val === 'undefined' || val == null) {
        elem[elem.length] = `<${key} />`
      } else if (typeof val === 'object' && val.constructor == Array) {
        elem[elem.length] = this.array_to_xml(key, val)
      } else if (typeof val === 'object') {
        elem[elem.length] = this.hash_to_xml(key, val)
      } else {
        elem[elem.length] = this.scalar_to_xml(key, val)
      }
    } else {
      attr[attr.length] = ` ${key.substring(1)}="${this.xml_escape(val)}"`
    }
  }
  const jattr = attr.join('')
  let jelem = elem.join('')
  if (typeof name === 'undefined' || name == null) {
    // no tag
  } else if (elem.length > 0) {
    if (jelem.match(/\n/)) {
      jelem = `<${name}${jattr}>\n${jelem}</${name}>\n`
    } else {
      jelem = `<${name}${jattr}>${jelem}</${name}>\n`
    }
  } else {
    jelem = `<${name}${jattr} />\n`
  }
  return jelem
}

//  method: array_to_xml( tagName, array )

XML.ObjTree.prototype.array_to_xml = function(name, array) {
  const out = []
  for (let i = 0; i < array.length; i++) {
    const val = array[i]
    if (typeof val === 'undefined' || val == null) {
      out[out.length] = `<${name} />`
    } else if (typeof val === 'object' && val.constructor == Array) {
      out[out.length] = this.array_to_xml(name, val)
    } else if (typeof val === 'object') {
      out[out.length] = this.hash_to_xml(name, val)
    } else {
      out[out.length] = this.scalar_to_xml(name, val)
    }
  }
  return out.join('')
}

//  method: scalar_to_xml( tagName, text )

XML.ObjTree.prototype.scalar_to_xml = function(name, text) {
  if (name == '#text') {
    return this.xml_escape(text)
  }
  return `<${name}>${this.xml_escape(text)}</${name}>\n`
}

//  method: xml_escape( text )

XML.ObjTree.prototype.xml_escape = function(text) {
  return `${text}`
    .replace(/&/g, '&amp;')
    .replace(/</g, '&lt;')
    .replace(/>/g, '&gt;')
    .replace(/"/g, '&quot;')
}

export default XML

json_xml_300">json 转为xml

const getIncoming = (id, data) => {
  return data.filter(item => item.targetRef === id).map(items => items.id)
}
const getOutGoing = (id, data) => {
  return data.filter(item => item.sourceRef === id).map(items => items.id)
}
const getLabel = (data, labelStyle) => {
  const keyWord = ['isBold', 'isItalic', 'isStrikeThrough', 'isUnderline', 'fontFamily', 'size']
  const arr = data.filter(item => {
    return keyWord.find(key => {
      return key in labelStyle
    })
  })
  return arr.map(item => {
    const obj = {}
    keyWord.forEach(key => {
      if (labelStyle[key]) {
        obj[key === 'fontFamily' ? 'name' : key] = labelStyle[key] || ''
      }
    })
    return {
      '-id': item.id,
      'omgdc:Font': obj
    }
  })
}
export function convertJsonToBpmn(jsonData) {
  if (!jsonData || !Object.keys(jsonData).length) return {}
  const result = {
    definitions: {
      '-xmlns': 'http://www.omg.org/spec/BPMN/20100524/MODEL',
      '-xmlns:bpmndi': 'http://www.omg.org/spec/BPMN/20100524/DI',
      '-xmlns:omgdi': 'http://www.omg.org/spec/DD/20100524/DI',
      '-xmlns:omgdc': 'http://www.omg.org/spec/DD/20100524/DC',
      '-xmlns:xsi': 'http://www.w3.org/2001/XMLSchema-instance',
      '-xmlns:bioc': 'http://bpmn.io/schema/bpmn/biocolor/1.0',
      '-xmlns:color': 'http://www.omg.org/spec/BPMN/non-normative/color/1.0',
      '-id': 'sid-38422fae-e03e-43a3-bef4-bd33b32041b2',
      '-targetNamespace': 'http://bpmn.io/bpmn',
      '-exporter': 'bpmn-js (https://demo.bpmn.io)',
      '-exporterVersion': '5.1.2',
      process: {
        '-id': 'Process_1',
        '-isExecutable': 'true',
        task: [],
        sequenceFlow: []
      },
      'bpmndi:BPMNDiagram': {
        '-id': 'BpmnDiagram_1',
        'bpmndi:BPMNPlane': {
          '-id': 'BpmnPlane_1',
          '-bpmnElement': 'Process_1',
          'bpmndi:BPMNShape': [],
          'bpmndi:BPMNEdge': []
        }
      },
      'bpmndi:BPMNLabelStyle': {}
    }
  }

  // Convert tasks
  jsonData.nodeLists.forEach(task => {
    const taskId = task.config.id
    const incoming = getIncoming(taskId, jsonData.lines)
    const outGoing = getOutGoing(taskId, jsonData.lines)
    const obj = {
      '-id': taskId
    }
    if (incoming.length > 1) {
      obj.incoming = incoming
    } else if (incoming.length === 1) {
      obj.incoming = incoming[0]
    }
    if (outGoing.length > 1) {
      obj.outgoing = outGoing
    } else if (outGoing.length === 1) {
      obj.outgoing = outGoing[0]
    }

    result.definitions.process.task.push(obj)
    const { x, y, width, height, labelStyle } = task.config

    const element = {
      '-id': `${taskId}_di`,
      '-bpmnElement': taskId,
      'omgdc:Bounds': {
        '-x': x,
        '-y': y,
        '-width': width,
        '-height': height
      },
      'bpmndi:BPMNLabel': {}
    }
    if (labelStyle && Object.keys(labelStyle).length) {
      const { x, y, width, height, id } = labelStyle
      element['bpmndi:BPMNLabel']['-labelStyle'] = id
      element['bpmndi:BPMNLabel']['omgdc:Bounds'] = {
        '-x': x,
        '-y': y,
        '-width': width,
        '-height': height
      }
      result.definitions['bpmndi:BPMNLabelStyle'] = getLabel(jsonData.nodeLists, labelStyle)
    }
    // Convert BPMN shapes
    result.definitions['bpmndi:BPMNDiagram']['bpmndi:BPMNPlane']['bpmndi:BPMNShape'].push(element)
  })

  // Convert sequence flows
  jsonData.lines.forEach(line => {
    const sequenceFlowId = line.id
    const sourceRef = line.sourceRef
    const targetRef = line.targetRef

    result.definitions.process.sequenceFlow.push({
      '-id': `${sequenceFlowId}`,
      '-name': line.name,
      '-sourceRef': sourceRef,
      '-targetRef': targetRef
    })

    // Convert BPMN edges
    result.definitions['bpmndi:BPMNDiagram']['bpmndi:BPMNPlane']['bpmndi:BPMNEdge'].push({
      '-id': `${sequenceFlowId}_di`,
      '-bpmnElement': sequenceFlowId,
      'omgdi:waypoint': line.point.map(p => {
        return { '-x': p.x, '-y': p.y }
      }),
      'bpmndi:BPMNLabel': {
        'omgdc:Bounds': {
          '-x': line.x,
          '-y': line.y,
          '-width': line.width,
          '-height': line.height
        }
      }
    })
  })

  return result
}


http://www.niftyadmin.cn/n/4966243.html

相关文章

大厂考核重点:mysql索引面试题

很多同学面对Mysql索引相关的面试题都是死记硬背的&#xff0c;这肯定是不行的&#xff0c;也不容易记住&#xff0c;所以大家还是要循循渐进&#xff0c;从理解开始&#xff0c;慢慢掌握&#xff0c;当然对于想要准备面试题的同学&#xff0c;这几个问题是需要记住并理解的&am…

C语言易忘、易混

C语言易忘 1 printf函数和putchar函数2 scanf函数与getchar函数3 goto语句4 字符数组与字符串区别5 字符串的输入输出5.1 gets()5.2 fgets()5.3 puts()5.4 fputs() 6 main函数与exit函数7 防止头文件重复包含8 字符串处理函数8.1 strcpy()8.2 strncpy()8.3 strcat()8.4 strncat…

Sketch 98 中文版-mac矢量绘图设计

Sketch是一款专为Mac操作系统设计的矢量图形编辑软件&#xff0c;被广泛应用于UI/UX设计、网页设计、移动应用设计等领域。Sketch提供了各种工具和功能&#xff0c;包括绘图、图形设计、排版等&#xff0c;可以帮助设计师轻松地创建高质量的矢量图形和模型。Sketch的主要特点包…

2023前端面试笔记 —— HTML5

系列文章目录 内容链接2023前端面试笔记HTML5 文章目录 系列文章目录前言一、HTML 文件中的 DOCTYPE 是什么作用二、HTML、XML、XHTML 之间有什么区别三、前缀为 data- 开头的元素属性是什么四、谈谈你对 HTML 语义化的理解五、HTML5 对比 HTML4 有哪些不同之处六、meta 标签有…

【100天精通python】Day45:python网络爬虫开发_ Scrapy 爬虫框架

目录 1 Scrapy 的简介 2 Scrapy选择器 3 快速创建Scrapy 爬虫 4 下载器与爬虫中间件 5 使用管道Pielines 1 Scrapy 的简介 Scrapy 是一个用于爬取网站数据并进行数据提取的开源网络爬虫框架。它使用 Python 编程语言编写&#xff0c;并提供了一套强大的工具和库&#xff0…

【C++】C++11中比较重要的内容介绍

C11 前言正式开始统一的初始化列表{ }初始化对象{ }为容器初始化赋值运算符重载也支持{} 声明autodecltypenullptr STL中一些变化arrayforward_listunordered_map 和 unordered_set 右值引用表达式左值和右值左值右值 右值引用的使用场景移动构造和移动赋值重载右值分类移动构造…

libevent源码学习3---事件event

libevent源码学习3—事件event libevent 的基本操作单元是事件。每个事件代表一组条件的集合, 这些条件包括: 文件描述符已经就绪, 可以读取或者写入文件描述符变为就绪状态,可以读取或者写入(仅对于边沿触发 IO)超时事件发生某信号用户触发事件 所有事件具有相似的生命周期。…

Vue2数据发生变化但页面未改变

遇到了一个神奇的bug 项目是Vue2的项目&#xff0c;检查了代码没有问题&#xff0c;页面上操作了删除按钮&#xff0c;实际这个数据删除了&#xff0c;但是页面上不会重新渲染&#xff0c;这条数据还在。查找原因&#xff1a; 发现是&#xff0c;对象中的属性没有初始化&#x…