如何使用PHP将HTML转换为JSON?

我可以使用JsontoHtml库将JSON转换为HTML。 现在,我需要将现在的HTML转换为JSON,如本网站所示。 当查看代码时,我发现了以下脚本:

<script> $(function(){ //HTML to JSON $('#btn-render-json').click(function() { //Set html output $('#html-output').html( $('#html-input').val() ); //Process to JSON and format it for consumption $('#html-json').html( FormatJSON(toTransform($('#html-output').children())) ); }); }); //Convert obj or array to transform function toTransform(obj) { var json; if( obj.length > 1 ) { json = []; for(var i = 0; i < obj.length; i++) json[json.length++] = ObjToTransform(obj[i]); } else json = ObjToTransform(obj); return(json); } //Convert obj to transform function ObjToTransform(obj) { //Get the DOM element var el = $(obj).get(0); //Add the tag element var json = {'tag':el.nodeName.toLowerCase()}; for (var attr, i=0, attrs=el.attributes, l=attrs.length; i<l; i++){ attr = attrs[i]; json[attr.nodeName] = attr.value; } var children = $(obj).children(); if( children.length > 0 ) json['children'] = []; else json['html'] = $(obj).text(); //Add the children for(var c = 0; c < children.length; c++) json['children'][json['children'].length++] = toTransform(children[c]); return(json); } //Format JSON (with indents) function FormatJSON(oData, sIndent) { if (arguments.length < 2) { var sIndent = ""; } var sIndentStyle = " "; var sDataType = RealTypeOf(oData); // open object if (sDataType == "array") { if (oData.length == 0) { return "[]"; } var sHTML = "["; } else { var iCount = 0; $.each(oData, function() { iCount++; return; }); if (iCount == 0) { // object is empty return "{}"; } var sHTML = "{"; } // loop through items var iCount = 0; $.each(oData, function(sKey, vValue) { if (iCount > 0) { sHTML += ","; } if (sDataType == "array") { sHTML += ("\n" + sIndent + sIndentStyle); } else { sHTML += ("\"" + sKey + "\"" + ":"); } // display relevant data type switch (RealTypeOf(vValue)) { case "array": case "object": sHTML += FormatJSON(vValue, (sIndent + sIndentStyle)); break; case "boolean": case "number": sHTML += vValue.toString(); break; case "null": sHTML += "null"; break; case "string": sHTML += ("\"" + vValue + "\""); break; default: sHTML += ("TYPEOF: " + typeof(vValue)); } // loop iCount++; }); // close object if (sDataType == "array") { sHTML += ("\n" + sIndent + "]"); } else { sHTML += ("}"); } // return return sHTML; } //Get the type of the obj (can replace by jquery type) function RealTypeOf(v) { if (typeof(v) == "object") { if (v === null) return "null"; if (v.constructor == (new Array).constructor) return "array"; if (v.constructor == (new Date).constructor) return "date"; if (v.constructor == (new RegExp).constructor) return "regex"; return "object"; } return typeof(v); } </script> 

在这里输入图像描述

现在,我需要在PHP中使用以下function。 我可以得到HTML数据。 所有我现在需要的是将JavaScript函数转换为PHP函数。 这可能吗? 我主要怀疑如下:

  • Javascript函数toTransform()的主要input是一个对象。 是否有可能通过PHP将HTML转换为对象?

  • 这个特定的JavaScript中的所有function都可以在PHP中使用吗?

请给我build议的想法。

当我试图根据给定的答案转换脚本标记到JSON,我得到错误。 当我在json2html网站上试用时,它显示如下: 在这里输入图像描述 ..如何实现相同的解决scheme?

如果您能够获得表示HTML的DOMDocument对象,那么您只需要recursion地遍历它并构build所需的数据结构。

将HTML文档转换为DOMDocument应该如此简单:

 function html_to_obj($html) { $dom = new DOMDocument(); $dom->loadHTML($html); return element_to_obj($dom->documentElement); } 

然后, $dom->documentElement一个简单的遍历,它给出了你描述的结构的types可能是这样的:

 function element_to_obj($element) { $obj = array( "tag" => $element->tagName ); foreach ($element->attributes as $attribute) { $obj[$attribute->name] = $attribute->value; } foreach ($element->childNodes as $subElement) { if ($subElement->nodeType == XML_TEXT_NODE) { $obj["html"] = $subElement->wholeText; } else { $obj["children"][] = element_to_obj($subElement); } } return $obj; } 

testing用例

 $html = <<<EOF <!DOCTYPE html> <html lang="en"> <head> <title> This is a test </title> </head> <body> <h1> Is this working? </h1> <ul> <li> Yes </li> <li> No </li> </ul> </body> </html> EOF; header("Content-Type: text/plain"); echo json_encode(html_to_obj($html), JSON_PRETTY_PRINT); 

产量

 { "tag": "html", "lang": "en", "children": [ { "tag": "head", "children": [ { "tag": "title", "html": " This is a test " } ] }, { "tag": "body", "html": " \n ", "children": [ { "tag": "h1", "html": " Is this working? " }, { "tag": "ul", "children": [ { "tag": "li", "html": " Yes " }, { "tag": "li", "html": " No " } ], "html": "\n " } ] } ] } 

回答更新的问题

上面提出的解决scheme不适用于<script>元素,因为它不是被parsing为DOMText ,而是被parsing为DOMCharacterData对象。 这是因为PHP中的DOM扩展基于libxml2 ,它将HTMLparsing为HTML 4.0,而在HTML 4.0中, <script>的内容是CDATAtypes,而不是#PCDATA

你有两个解决这个问题的方法。

  1. 简单但不是非常可靠的解决scheme是将LIBXML_NOCDATA标志添加到DOMDocument::loadHTML 。 (我实际上不是100%确定这是否适用于HTMLparsing器。)

  2. 在我看来,更困难的是,更好的解决scheme是在recursion之前testing$subElement->nodeType时添加额外的testing。 recursion函数将变成:

 function element_to_obj($element) { echo $element->tagName, "\n"; $obj = array( "tag" => $element->tagName ); foreach ($element->attributes as $attribute) { $obj[$attribute->name] = $attribute->value; } foreach ($element->childNodes as $subElement) { if ($subElement->nodeType == XML_TEXT_NODE) { $obj["html"] = $subElement->wholeText; } elseif ($subElement->nodeType == XML_CDATA_SECTION_NODE) { $obj["html"] = $subElement->data; } else { $obj["children"][] = element_to_obj($subElement); } } return $obj; } 

如果你碰到另一个这种types的bug,你应该做的第一件事是检查节点$subElement的types,因为我的简短示例函数没有处理其他许多可能性 。

此外,您会注意到libxml2必须修正HTML中的错误,才能为其构buildDOM。 这就是为什么即使没有指定<html><head>元素也会出现的原因。 您可以通过使用LIBXML_HTML_NOIMPLIED标志来避免这种情况。

与脚本的testing用例

 $html = <<<EOF <script type="text/javascript"> alert('hi'); </script> EOF; header("Content-Type: text/plain"); echo json_encode(html_to_obj($html), JSON_PRETTY_PRINT); 

产量

 { "tag": "html", "children": [ { "tag": "head", "children": [ { "tag": "script", "type": "text\/javascript", "html": "\n alert('hi');\n " } ] } ] }