Я могу конвертировать JSON в HTML с помощью библиотеки JsontoHtml . Теперь мне нужно преобразовать текущий 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. Я могу получить данные HTML. Теперь мне нужно преобразовать функцию JavaScript в функцию PHP. Это возможно? Мои основные сомнения заключаются в следующем:
Основной вход для функции Javascript toTransform()
– это объект. Можно ли преобразовать HTML в объект через PHP?
Все ли функции, присутствующие в этом JavaScript, доступны в PHP?
Пожалуйста, предложите мне эту идею.
Когда я попытался преобразовать тег скрипта в json в соответствии с предоставленным ответом, я получаю ошибки. Когда я попробовал это на сайте json2html, он показал следующее: .. Как достичь такого же решения?
Если вы можете получить объект DOMDocument
представляющий ваш HTML, вам просто нужно пройти его рекурсивно и построить структуру данных, которая вам нужна.
Преобразование HTML-документа в DOMDocument
должно быть таким простым, как это:
function html_to_obj($html) { $dom = new DOMDocument(); $dom->loadHTML($html); return element_to_obj($dom->documentElement); }
Затем простой обход $dom->documentElement
который описывает описанную структуру, может выглядеть так:
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; }
Прецедент
$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 " } ] } ] }
Ответ на обновленный вопрос
Предлагаемое выше решение не работает с элементом <script>
, поскольку оно анализируется не как DOMText
, а как объект DOMCharacterData
. Это связано с тем, что расширение DOM в PHP основано на libxml2
, которое анализирует ваш HTML как HTML 4.0, а в HTML 4.0 содержимое <script>
имеет тип CDATA
а не #PCDATA
.
У вас есть два решения этой проблемы.
Простым, но не очень надежным решением было бы добавить флаг DOMDocument::loadHTML
в DOMDocument::loadHTML
. (На самом деле я на самом деле не уверен, что это работает для парсера HTML.)
Более сложное, но, на мой взгляд, лучшее решение – добавить дополнительный тест, когда вы тестируете $subElement->nodeType
перед рекурсией. Рекурсивной функцией станет:
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; }
Если вы нажмете на другую ошибку этого типа, первое, что вам нужно сделать, это проверить тип узла $subElement
, потому что существует много других возможностей, с $subElement
моя короткая $subElement
функция не справлялась.
Кроме того, вы заметите, что libxml2
должен исправить ошибки в вашем HTML, чтобы иметь возможность создавать DOM для него. Вот почему элементы <html>
и <head>
появятся, даже если вы их не укажете. Вы можете избежать этого, используя флаг LIBXML_HTML_NOIMPLIED
.
Тест-сценарий со сценарием
$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 " } ] } ] }