Преобразование HTML-формы в JSON Equivalent [duplicate]

Несколько перестановок ваших предложенных функций работают, но только если вы указываете аргумент character.only как TRUE. Быстрый пример:

lapply(x, require, character.only = TRUE)
15
задан Ganesh Babu 2 May 2014 в 14:16
поделиться

2 ответа

Если вы можете получить объект 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
ответ дан scozy 25 August 2018 в 18:57
поделиться
0
ответ дан Amir Forsati 25 August 2018 в 18:57
поделиться