Как конвертировать HTML в JSON с помощью PHP?


Я могу конвертировать 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>

enter image description here

Теперь мне нужно использовать следующую функцию в PHP. Я могу получить данные HTML. Все, что мне сейчас нужно, - это преобразовать функцию JavaScript в функцию PHP. Возможно ли это? Мои основные сомнения заключаются в следующем:

  • Основной входной сигнал для Функция Javascript toTransform() является объектом. Можно ли преобразовать HTML в объект с помощью PHP?

  • Все ли функции, присутствующие в этом конкретном JavaScript, доступны в PHP?

Пожалуйста, предложите мне эту идею.

Когда я попытался преобразовать тег скрипта в json в соответствии с данным ответом, я получаю ошибки. Когда я попробовал это на сайте json2html, это выглядело так:enter image description here.. Как добиться того же решения?

Author: Ganesh Babu, 2014-04-14

2 answers

Если вы можете получить объект 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.

У вас есть два решения для этого проблема.

  1. Простым, но не очень надежным решением было бы добавить флаг LIBXML_NOCDATA в DOMDocument::loadHTML. ( Я на самом деле не уверен на 100%, работает ли это для синтаксического анализатора HTML.)

  2. Более сложным, но, на мой взгляд, лучшим решением является добавление дополнительного теста, когда вы тестируете $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, потому что существует множество других возможностей, с которыми не справилась моя функция короткого примера.

Кроме того, вы заметите, что 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        "
                }
            ]
        }
    ]
}
 20
Author: scozy, 2014-05-02 14:27:09

Я предполагаю, что ваша html-строка хранится в переменной $html. Поэтому вам следует сделать:

$dom = new DOMDocument();
$dom->loadHTML($html);

foreach($dom->getElementsByTagName('*') as $element){
    $result[] = ["type" => $element->tagName, "value" => $element->nodeValue];
}

$json = json_encode($result, JSON_UNESCAPED_UNICODE);

Примечание: Этот алгоритм не поддерживает теги "родитель-потомок" и извлекает все теги как родительские и анализирует их все в отсортированной очереди.

 0
Author: Amir Forsati, 2018-05-30 17:17:35