首页 > 试题广场 >

dom节点转成json数据

[编程题]dom节点转成json数据
  • 热度指数:3269 时间限制:C/C++ 3秒,其他语言6秒 空间限制:C/C++ 256M,其他语言512M
  • 算法知识视频讲解
页面上存在id=jsContainer的节点A,系统会随机在节点A中生成文档片段,请按照如下需求实现 dom2json 函数
1、dom2json需要分析整个节点A的dom结构,并将其结构转换为对应的json对象
2、需要获取dom结构的标签名称(tag),所有属性(attributes),子节点(children)
3、文档片段中的属性形式均为 name="value",解析之后的格式为{name: value}, 属性值为String类型,不需要做解析
4、随机生成的文档片段中,只包含 nodeType 为1(element)和3(text)的节点,不需要考虑其他节点类型
5、纯文本也视为一个节点, json格式为 {tag: 'text', content: '文本内容'},content为文本内容执行trim后的结果,如果该结果为空,则忽略当前节点
6、返回结果中的标签名称不区分大小写
7、如果节点不包含属性值或者子节点,其对应的结果中需要保留attributes以及children字段,例如 {tag: 'div', attributes: {}, children: []}
8、当前界面执行dom2json之后的结果为如下图所示
9、请不要手动修改html和css
10、不要使用第三方插件
function dom2json() {
    const fn = (node) => {
        const obj = {
            tag: node.nodeName.toLowerCase(),
            attributes: [].reduce.call(node.attributes, (acc, cur) => {
                acc[cur.nodeName] = cur.value
                return acc
            }, {}),
            children: Array.from(node.childNodes).reduce((acc, cur) => {
                if (cur.nodeName === '#text') {
                    const context = cur.nodeValue.trim()
                    if (context) acc.push({
                        tag: 'text',
                        context: context
                    })
                } else acc.push(fn(cur))
                return acc
            }, [])
        }
        return obj
    }
    return fn(jsContainer)
}

发表于 2021-12-01 15:06:50 回复(0)
为啥发出来后没有语法高亮了
function dom2json() {
    function createObj(node) {
        const obj = {};
        const tag = node.nodeName.toLocaleLowerCase();
        // 过滤子节点列表
        const childList = Array.from(node.childNodes).filter((item) => {
            const name = item.nodeName;
            return (name === '#text' && item.data.trim() !== '') || name !== '#text';
        });

        // 生成 tag
        if (tag === '#text') {
            obj.tag = 'text';
            obj.content = node.data.trim();
        } else {
            obj.tag = tag;
        }

        // 生成 attributes
        if (node.attributes) {
            obj.attributes = {};
            for (let i = 0; i < node.attributes.length; i++) {
                const { name, value } = node.attributes[i];
                obj.attributes[name] = value;
            }
        }

        // 生成 children
        if (childList.length !== 0) {
            obj.children = [];
            for (let i = 0; i < childList.length; i++) {
                obj.children.push(createObj(childList[i]));        
            }
        }

        return obj;
    }

    const jsContainer = document.getElementById('jsContainer');
    return createObj(jsContainer);
}


发表于 2021-08-19 14:10:01 回复(0)
说好的tagName不区分大小写,测试必须小写。。
发表于 2021-07-21 10:48:41 回复(0)
function dom2json() {
        var div = document.getElementById('jsContainer');
        function splitDom(element) {
          var obj = {
            tag'',
            attributes: {},
            children: []
          };
          // 设置tag
          if (element.nodeName) {
            obj.tag = element.nodeName.toLowerCase();
          }
          if (element.nodeName == '#text') {
            obj.tag = 'text';
            delete obj.attributes;
            delete obj.children;
            obj.content = element.nodeValue.trim();
            return obj;
          }
          // 设置attributes
          var attrs = element.attributes;
          for (let i = 0i < attrs.lengthi++) {
            obj.attributes[attrs.item(i).name] = attrs.item(i).value;
          }
          // 设置children
          if (element.childNodes) {
            for (let i = 0i < element.childNodes.lengthi++) {
              var child = element.childNodes.item(i);
              if (child.nodeName == '#text' && child.nodeValue.trim() == '') {
                continue;
              } else {
                obj.children.push(splitDom(element.childNodes[i]));
              }
            }
          }
          return obj;
        }
        return splitDom(div);
      }
发表于 2022-02-17 11:40:51 回复(0)
function dom2json() {
    let div = document.getElementById('jsContainer');
    function solve(item) {
        let type = item.nodeType;
        if (type === 3) { //说明有可能是文本类型
            if (item.data.trim() === '')
                return null;
            else {
                return {
                    'tag': 'text',
                    'content': item.data.trim()
                }
            }
        } else {
            let now = {};
            now.tag = item.nodeName.toLowerCase();
            now.attributes = [...item.attributes].reduce((pre, now) => {
                pre[now.nodeName] = now.nodeValue;
                return pre;
            }, {})
            now.children = [...item.childNodes].reduce((pre, now) => {
                let result = solve(now);
                if (result) {
                    pre.push(result);
                }
                return pre;
            }, [])
            return now;
        }
    }
    return solve(div);
}

测试没问题的啊 自己会了就行了 爱过不过吧 淦

发表于 2022-03-24 21:55:09 回复(0)
不是要返回JSON吗????
发表于 2021-08-26 16:19:09 回复(0)
虽然测试没过,但是我坚信我是对的!!!
const dom2json = (root, resObj = {}) => {
            resObj.tag = root.tagName.toLowerCase() || root.nodeName.slice(1);
            let attrs = root.getAttributeNames().reduce((prev, name) => (prev[name] = root.getAttribute(name)) && prev, {});
            Object.keys(attrs).length && (resObj.attributes = attrs);

            const nodes = root.childNodes.length ? [...root.childNodes]
                .filter(nd => nd.nodeType === 1 || (nd.nodeType === 3 && nd.textContent.trim()))
                .map(nd => nd.nodeType === 3 ? { tag: nd.nodeName.slice(1), content: nd.textContent.trim() } : nd) : [];

            if (!Array.isArray(resObj.children)) resObj.children = [];

            nodes.forEach(nd => resObj.children.push(nd.tag === "text" ? nd : dom2json(nd)))
            return resObj
        }

发表于 2024-01-21 23:19:33 回复(0)
我觉得我的没问题,但是验证不通过 
function dom2json() {
        const jsContainer = document.getElementById("jsContainer");
        let obj = {};
        return setObj(obj, jsContainer);
      }
      // 组成对象的函数
      function setObj(obj, el) {
        let newObj = obj;
        let attributes = {};
        for (let key of el.attributes) {
          attributes[key.name] = key.value;
        }
        newObj = {
          tag: el.tagName.toLowerCase(),
          attributes: attributes,
        };
        if(el.childNodes.length > 0 ){
            newObj.children=[];
            el.childNodes.forEach((i) => {
            if (i.nodeName == "#text") {
              let text = i.nodeValue.replace(/\\n\s*/g, "").trim();
              text &&
                text !== "" &&
                newObj.children.push({
                  tag: "text",
                  content: text,
                });
            } else {
              newObj.children.push(setObj({}, i));
            }
          });
       
        }
          return newObj;
      }
     

发表于 2023-12-28 16:52:46 回复(0)
测试有问题,Console中用例执行返回true,但测试执行结果是null
发表于 2023-12-22 11:57:14 回复(1)
function dom2json() {
  const dom = document.getElementById('jsContainer');
  const fn = (node) => {
    if (node.nodeType === 3) {
      if (node.nodeValue.trim()) {
        // 文本
        return {
            tag: 'text',
            content: node.nodeValue.trim(),
        };
      }
      return null;
    }
    return {
      tag: node.tagName.toLowerCase(),
      attributes: Array.prototype.reduce.call(node.attributes, (acc, cur) => {
        acc[cur.nodeName] = cur.value;
        return acc;
      }, {}),
      children: node.childNodes.length > 0 ? Array.prototype.reduce.call(node.childNodes, (acc, cur) => {
        const item = fn(cur);
        if (item) {
          acc.push(item);
        }
        return acc;
      }, []) : undefined,
    };
  }
  return fn(dom);
}

发表于 2023-07-29 00:55:12 回复(0)
类似Obeject.values和Object.keys在当前例子中都不能使用,需要替换成其他的循环达到效果
function dom2json() {
      let jsContainer = document.querySelector("#jsContainer");
      function fn(el) {
        let res = {};
        res.tag = el.nodeName.replace(/\#/, "").toLowerCase();
        let attr = el.attributes;
        res.attributes = {};
        if (attr) {
            for(let i = 0; i < attr.length; i++){
                res.attributes[attr[i].nodeName] = attr[i].value
            }
        }
        if (el.childNodes) {
          res.children = [];
          for (let i = 0; i < el.childNodes.length; i++) {
            let data = {};
            let tagName = el.childNodes[i].nodeName
              .replace(/\#/, "")
              .toLowerCase();

            if (tagName == "text") {
              data.tag = tagName;
              let content = el.childNodes[i].nodeValue.trim();
              if (!content) continue;
              data.content = el.childNodes[i].nodeValue.trim();
            } else {
                data = fn(el.childNodes[i]);
            }
            if (JSON.stringify(data) != '{}') res.children.push(data);
          }
        }
        return res;
      }
      return fn(jsContainer);
    }

发表于 2022-10-14 14:16:46 回复(0)
const dom2json = (dom) => {
  const tag = dom.tagName.toLowerCase();
  const attributes = {};
  const children = [];
  const attrs = dom.attributes;
  for (let i = 0; i < attrs.length; i++) {
    const attr = attrs[i];
    attributes[attr.nodeName] = attr.nodeValue;
  }
  const childNodes = dom.childNodes;
  if (childNodes && childNodes.length) {
    for (let i = 0; i < childNodes.length; i++) {
      const child = childNodes[i];
      if (child.nodeType === 1) {
        children.push(dom2json(child));
      } else if (child.nodeType === 3) {
        const content = child.nodeValue.trim();
        if (content) {
          children.push({
            tag: "text",
            content,
          });
        }
      }
    }
  }
  return {
    tag,
    attributes,
    children,
  };
};


不考虑最外层节点为文本节点的情况
发表于 2022-09-17 11:03:41 回复(0)
     const getAttr = (node) => {
        const attribute = {};
        if (node.attributes?.length && node.nodeType === 1) {
          const attributes = { ...node.attributes };

          for (const key in attributes) {
            let k = attributes[key].nodeName;
            let v = attributes[key].nodeValue;
            Object.assign(attribute, { [k]: v });
          }
          return attribute;
        } else {
          return null;
        }
      };
      function dom2json(node) {
        node.obj = {};
        const { obj } = node;
        if (node.nodeType === 1) {
          // 非文本节点
          obj.tag = node.tagName.toLowerCase();
        }
        if (node.nodeType === 3 && node.data.trim() !== "") {
          // 文本节点
          obj.tag = "text";
          obj.content = node.data.trim();
        }

        if (getAttr(node)) {
          obj.attributes = getAttr(node);
        }

        const newArrNode = Array.from(node.childNodes).filter(
          (cnode) =>
            cnode.nodeType === 1 ||
            (cnode.nodeType === 3 && cnode.data.trim() !== "")
        );

        if (node.childNodes && newArrNode.length) {
          obj.children = [];
          // 符合情况的子节点
          newArrNode.forEach((cnode) => {
            obj.children.push(dom2json(cnode));
          });
        }

        return obj;
      }
      let p = dom2json(document.querySelector("#jsContainer"));
      console.log(JSON.stringify(p));

发表于 2022-08-24 16:24:56 回复(0)
function dom2json(dom) {
    if(!dom) dom=document.querySelector('#jsContainer')
    let model
    if (dom.nodeType == 1) {
        model={tag:'',attributes:{},children:[]}
        model.tag = dom.localName
        let len = dom.attributes.length
        if(len){
            for (let i = 0; i < len; i++) {
                let key=dom.attributes.item(i).nodeName
                model.attributes[key]= dom.getAttribute(key)
            }
        }
        let cLen = dom.childNodes.length
        if (cLen) {
            for (let i = 0; i < cLen; i++) {
                if(dom2json(dom.childNodes[i])){
                    model.children.push(dom2json(dom.childNodes[i]))
                }
            }
        }
    } else if (dom.nodeType == 3) {
        let text = dom.textContent.trim()
        if (text) model={tag:'text',content:text}
    }
    return model
}
let result=dom2json()

发表于 2022-05-04 20:15:05 回复(0)
function dom2json() {
            let res = function process(ele, obj = {}) {
                if (ele.nodeType == 3) {
                    if (ele.nodeValue.trim() != '') {
                        obj['tag'] = 'text'
                        obj['content'] = ele.nodeValue.trim()
                        return obj
                    } else {
                        return
                    }
                }
                obj['tag'] = ele.tagName.toLowerCase()
                obj['attributes'] = {}
                if (ele.className) {
                    obj['attributes']['class'] = ele.className
                }
                if (ele.id) {
                    obj['attributes']['id'] = ele.id
                }
                if (ele.getAttribute('style')) {
                    obj['attributes']['style'] = ele.getAttribute('style')
                }
                let data = ele.dataset
                Object.keys(data).forEach((key) => {
                    obj['attributes']['data-' + key] = data[key]
                })
                obj['children'] = []
                let childrenNodes = ele.childNodes
                for (let i = 0; i < childrenNodes.length; i++) {
                    if (childrenNodes[i].nodeType != 2) {
                        let child = process(childrenNodes[i])
                        if (child) {
                            obj['children'].push(child)
                        }
                    }
                }
                return obj
            }
            return JSON.stringify(res(jsContainer))
        }

谁能告诉我我错哪了

发表于 2022-04-23 10:38:34 回复(0)
        function dom2json() {
            let container = document.querySelector('#jsContainer')
            return getDomData(container)   
        }

        function getDomData(node) {
            let nodeType = node.nodeType
            let obj = {}
            if(nodeType === 1 || nodeType === 3 && node.textContent.trim().length > 0) {
                let attributes = {}, children = []
                if(nodeType === 3) {
                    obj.tag = 'text'
                    obj.content = node.textContent.trim()
                }

                if(nodeType === 1) {
                    obj.tag = node.nodeName.toLowerCase()
                    Array.prototype.forEach.call(node.attributes, item => {
                        attributes[item.name] = item.value
                    })
                    obj.attributes = attributes
                }
            
                Array.prototype.forEach.call(node.childNodes, child => {
                    getDomData(child) && children.push(getDomData(child))
                })

                obj.children = children
                return obj
            }
        }

发表于 2022-04-09 22:27:40 回复(0)
function dom2json() {
    var container = document.getElementById('jsContainer');
    var obj = {
        tag: container.nodeName.toLowerCase(),
        attributes: getAtr(container),
        children: getChild(container)
    };
    
    console.log(JSON.parse(JSON.stringify(obj)));
    return obj;
    //获取所有子元素
    function getChild(ele){
        //只包含 nodeType 为1(element)和3(text)的节点
        //判断是否有子元素
        if(!ele.hasChildNodes()){
            return [];
        }else{
            var arr = []; 
            Array.from(ele.childNodes).forEach(item=>{
                if(item.nodeType==3){
                    if(item.textContent.trim()!=''){
                        arr.push({
                            tag:'text',
                            content:item.nodeValue.trim()
                        })
                    }
                }else{
                    arr.push({
                        tag: item.nodeName.toLowerCase(),
                        attributes: getAtr(item),
                        children: getChild(item)
                    })
                }
            })
            return arr;
        }
    }
    
    // 获取元素所有属性
    function getAtr(ele){
        var attrs = {};
        if(ele.attributes.length!=0){
            Array.from(ele.attributes).forEach(item=>{
                attrs[item.name]=item.value;
            })
        }
        return attrs;
    }
}

发表于 2022-02-18 17:13:01 回复(0)

浏览器没问题,真机过不去

function dom2json(node = document.querySelector('#jsContainer'), json = {}) {
    if (node.nodeType == '3') {
        json.tagName = 'text'
        json.content = node.textContent
        return json
    }

    json.tagName = node.tagName
    json.attributes = {}
    json.children = []
    const attributes = node.attributes
    Array.from(attributes).forEach(attr => {
        json.attributes[attr.localName] = attr.value
    })

    if (Array.from(node.childNodes).length) {
        json.children = []
        Array.from(node.childNodes).forEach(child => {
            json.children.push(dom2json(child))
        })
    }

    return json
}
发表于 2021-12-30 18:01:05 回复(0)

测试编译器无法通过 map() 函数,所以在dom.attributes获取属性时,要通过for循环来赋值;
测试编译器无法直接获取 dom.childNodes,需要通过Array.from() 转换成数组之后再进行遍历操作。

function dom2json() {
  const A = document.querySelector('#jsContainer')
  function process(dom) {
    let obj = {}
    // 获取所有节点标签 ==> nodeName
    obj.tag = dom.nodeName.toLowerCase().replace('#', '')
    // 文本text节点
    if (dom.nodeType === 3) {
      if (!dom.textContent.trim()) return
      obj.content = dom.nodeValue.trim()
    }
    if (dom.nodeType === 1) {
      obj.attributes = {}
      obj.children = []
      for (let i = 0; i < dom.attributes.length; i++) {
        obj.attributes[dom.attributes[i].name] = dom.attributes[i].value
      }
      Array.from(dom.childNodes).forEach(item => {
        if (!process(item)) return
        obj.children.push(process(item))
      })
    }
    return obj
  }
  return process(A)
}
发表于 2021-12-07 16:56:16 回复(0)
实际输出是 null 还是得考虑环境是不是不支持某些 api
我这里使用 
elem.getAttributeNames()
就踩坑了


function dom2json() {
  var cantainer = document.getElementById('jsContainer');
  // 将dom转换为json
  var json = getNodeJson(cantainer);
  getChildren(cantainer, json);
  return json;

  function getAttribute(elem, json) {
    // 下面这个接口在测试用环境不支持
    // elem.getAttributeNames().forEach(function (name) {
    //   json.attributes[name] = elem.getAttribute(name);
    // });

    var attrs = elem.attributes;
    for (var i = 0; i < attrs.length; i++) {
      var attr = attrs[i];
      json.attributes[attr.name] = attr.value;
    }
  }

  function getNodeJson(elem) {
    return {
      tag: elem.tagName.toLocaleLowerCase(),
      attributes: {},
      children: [],
    };
  }

  function getChildren(elem, json) {
    // 获取当前节点的属性值
    getAttribute(elem, json);
    // 获取全部子节点
    var children = elem.childNodes;
    for (var i = 0; i < children.length; i++) {
      var child = children[i];
      if (child.nodeType === 1) {
        // 是元素节点
        // 将元素节点转换为json
        var childJson = getNodeJson(child);
        // 递归获取子节点的属性值 和 子节点的子节点
        getChildren(child, childJson);
        json.children.push(childJson);
      } else if (child.nodeType === 3 && child.nodeValue.trim()) {
        // 是文本节点,并且文本节点不为空
        json.children.push({
          tag: 'text',
          content: child.nodeValue.trim(),
        });
      }
    }
  }
}



发表于 2021-11-11 17:39:47 回复(0)