如何使用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>
的内容是CDATA
types,而不是#PCDATA
。
你有两个解决这个问题的方法。
-
简单但不是非常可靠的解决scheme是将
LIBXML_NOCDATA
标志添加到DOMDocument::loadHTML
。 (我实际上不是100%确定这是否适用于HTMLparsing器。) -
在我看来,更困难的是,更好的解决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 " } ] } ] }