将HTML映射到JSON

nim*_*rod 58 html javascript json

我正在尝试将HTML映射到JSON,结构完整.是否有任何图书馆可以做到这一点,还是我需要自己编写?我想如果没有html2json库,我可以把xml2json库作为一个开始.毕竟,html只是xml的一个变种吗?

更新:好的,我应该举一个例子.我想要做的是以下内容.解析一串html:

<div>
  <span>text</span>Text2
</div>
Run Code Online (Sandbox Code Playgroud)

像这样的json对象:

{
  "type" : "div",
  "content" : [
    {
      "type" : "span",
      "content" : [
        "Text2"
      ]
    },
    "Text2"
  ]
}
Run Code Online (Sandbox Code Playgroud)

注意:如果你没有注意到标签,我正在寻找Javascript的解决方案

Geo*_*ith 60

我刚刚编写了这个函数来做你想做的事情,尝试一下让我知道它是否对你不正常:

// Test with an element.
var initElement = document.getElementsByTagName("html")[0];
var json = mapDOM(initElement, true);
console.log(json);

// Test with a string.
initElement = "<div><span>text</span>Text2</div>";
json = mapDOM(initElement, true);
console.log(json);

function mapDOM(element, json) {
    var treeObject = {};

    // If string convert to document Node
    if (typeof element === "string") {
        if (window.DOMParser) {
              parser = new DOMParser();
              docNode = parser.parseFromString(element,"text/xml");
        } else { // Microsoft strikes again
              docNode = new ActiveXObject("Microsoft.XMLDOM");
              docNode.async = false;
              docNode.loadXML(element); 
        } 
        element = docNode.firstChild;
    }

    //Recursively loop through DOM elements and assign properties to object
    function treeHTML(element, object) {
        object["type"] = element.nodeName;
        var nodeList = element.childNodes;
        if (nodeList != null) {
            if (nodeList.length) {
                object["content"] = [];
                for (var i = 0; i < nodeList.length; i++) {
                    if (nodeList[i].nodeType == 3) {
                        object["content"].push(nodeList[i].nodeValue);
                    } else {
                        object["content"].push({});
                        treeHTML(nodeList[i], object["content"][object["content"].length -1]);
                    }
                }
            }
        }
        if (element.attributes != null) {
            if (element.attributes.length) {
                object["attributes"] = {};
                for (var i = 0; i < element.attributes.length; i++) {
                    object["attributes"][element.attributes[i].nodeName] = element.attributes[i].nodeValue;
                }
            }
        }
    }
    treeHTML(element, treeObject);

    return (json) ? JSON.stringify(treeObject) : treeObject;
}
Run Code Online (Sandbox Code Playgroud)

工作示例:http://jsfiddle.net/JUSsf/(在chrome中测试过,我无法保证完全支持浏览器 - 您必须对此进行测试).

它创建一个对象,其中包含您请求的格式的HTML页面的树结构,然后使用JSON.stringify()它包含在大多数现代浏览器中(IE8 +,Firefox 3+ .etc); 如果您需要支持旧版浏览器,可以包含json2.js.

它可以采用一个DOM element或一个string包含有效的XHTML作为参数(我相信,我不确定DOMParser()在某些情况下是否会因为设置而阻塞,"text/xml"或者它是否只是不提供错误处理.不幸的是"text/html"浏览器支持不佳).

您可以通过传递不同的值来轻松更改此函数的范围element.您传递的任何值都将是您的JSON映射的根.

请享用

  • @nimrod很高兴。我没听说过以太坊,在写这篇文章时我学到了很多东西。 (2认同)

mb2*_*b21 20

GitHub上的html2json和json2html是基于John Resig的htmlparser.js构建的,它包含了一些测试用例并且对我很有帮助.


Tha*_*you 8

代表复杂的HTML文档将是困难的,并且充满了极端情况,但我只是想分享几种技术来展示如何开始这种程序.这个答案的不同之处在于它使用数据抽象和toJSON递归构建结果的方法

下面html2json是一个微小的函数,它将HTML节点作为输入,并返回一个JSON字符串作为结果.要特别注意代码是如何完全平坦的,但它仍然能够构建一个深度嵌套的树结构 - 所有这些都可能几乎没有复杂性

// data Elem = Elem Node

const Elem = e => ({
  toJSON : () => ({
    tagName: 
      e.tagName,
    textContent:
      e.textContent,
    attributes:
      Array.from(e.attributes, ({name, value}) => [name, value]),
    children:
      Array.from(e.children, Elem)
  })
})

// html2json :: Node -> JSONString
const html2json = e =>
  JSON.stringify(Elem(e), null, '  ')
  
console.log(html2json(document.querySelector('main')))
Run Code Online (Sandbox Code Playgroud)
<main>
  <h1 class="mainHeading">Some heading</h1>
  <ul id="menu">
    <li><a href="/a">a</a></li>
    <li><a href="/b">b</a></li>
    <li><a href="/c">c</a></li>
  </ul>
  <p>some text</p>
</main>
Run Code Online (Sandbox Code Playgroud)

在前面的例子中,textContent得到了一点点屠杀.为了解决这个问题,我们引入了另一个数据构造函数TextElem.我们必须映射childNodes(而不是children)并选择返回正确的数据类型e.nodeType- 这使我们更接近我们可能需要的东西

// data Elem = Elem Node | TextElem Node

const TextElem = e => ({
  toJSON: () => ({
    type:
      'TextElem',
    textContent:
      e.textContent
  })
})

const Elem = e => ({
  toJSON : () => ({
    type:
      'Elem',
    tagName: 
      e.tagName,
    attributes:
      Array.from(e.attributes, ({name, value}) => [name, value]),
    children:
      Array.from(e.childNodes, fromNode)
  })
})

// fromNode :: Node -> Elem
const fromNode = e => {
  switch (e.nodeType) {
    case 3:  return TextElem(e)
    default: return Elem(e)
  }
}

// html2json :: Node -> JSONString
const html2json = e =>
  JSON.stringify(Elem(e), null, '  ')
  
console.log(html2json(document.querySelector('main')))
Run Code Online (Sandbox Code Playgroud)
<main>
  <h1 class="mainHeading">Some heading</h1>
  <ul id="menu">
    <li><a href="/a">a</a></li>
    <li><a href="/b">b</a></li>
    <li><a href="/c">c</a></li>
  </ul>
  <p>some text</p>
</main>
Run Code Online (Sandbox Code Playgroud)

无论如何,这只是问题的两次迭代.当然,你必须解决它们出现的极端情况,但是这种方法的好处在于它为你提供了很多灵活性来编码你想要的JSON格式 - 并且没有引入太多的复杂性

根据我的经验,你可以继续使用这种技术,并取得非常好的结果.如果这个答案对任何人都很有意思,并希望我能够扩展,请告诉我^ _ ^

相关:使用JavaScript的递归方法:构建自己的JSON.stringify版本