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

Posted

技术标签:

【中文标题】如何使用 PHP 将 HTML 转换为 JSON?【英文标题】:How to convert HTML to JSON using PHP? 【发布时间】:2014-05-28 13:22:27 【问题描述】:

我可以使用 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 中使用以下函数。我可以获取 HTML 数据。我现在需要的只是将 javascript 函数转换为 PHP 函数。这可能吗?我的主要疑惑如下:

Javascript 函数toTransform() 的主要输入是一个对象。是否可以通过 PHP 将 HTML 转换为对象?

此特定 JavaScript 中存在的所有函数在 PHP 中是否可用?

请给我建议。

当我尝试根据给出的答案将脚本标记转换为 json 时,我得到了错误。当我在json2html站点尝试它时,它显示如下: ..如何实现相同的解决方案?

【问题讨论】:

可以转换。 toTransform 不采用随机对象,它在 html 中获取一组子项(也许可以玩弄代码,看看它放入了什么,吐出什么)等等。不过,将它转换为 PHP 是你的工作,而不是我们的:) @user3036342 感谢您的建议。该输入是我感到困惑的。是否有任何 php 函数可用于在 Html 中获取子数组?我尝试将其类型转换为对象。但它没有用? javascript内置了dom解析,在php中可以使用domdocument php.net/manual/en/class.domdocument.php @Ganesh 您的问题是您出于某种原因试图将其转换为对象,输入是一个数组。执行 alert() 来检查 JavaScript 实际发送到这些函数的内容,然后您将能够更好地使其在您的 PHP 版本中返回相同的内容。如前所述,您可以使用 DomDocument。查看一个名为“PHPQuery”的库。它是 jQuery 的 PHP 版本,应该可以帮到你很多 与其寻找将html转换为json的方法,不如尝试将xml转换为json。你可以使用这个***.com/questions/8830599/php-convert-xml-to-json 【参考方案1】:

如果你能够获得一个代表你的HTML的DOMDocument对象,那么你只需要递归地遍历它并构造你想要的数据结构。

将您的 HTML 文档转换为 DOMDocument 应该像这样简单:

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

然后,对$dom-&gt;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        "
                
            ]
        
    ]


更新问题的答案

上面提出的解决方案不适用于&lt;script&gt; 元素,因为它不是解析为DOMText,而是解析为DOMCharacterData 对象。这是因为 PHP 中的 DOM 扩展基于 libxml2,,它将您的 HTML 解析为 HTML 4.0,而在 HTML 4.0 中,&lt;script&gt; 的内容类型为 CDATA 而不是 #PCDATA

对于这个问题,你有两个解决方案。

    简单但不太健壮的解决方案是将LIBXML_NOCDATA 标志添加到DOMDocument::loadHTML.(我实际上并不能100% 确定这是否适用于HTML 解析器。)

    更困难但我认为更好的解决方案是在递归之前测试$subElement-&gt;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的类型,因为存在many other possibilities,我的简短示例函数没有处理。

此外,您会注意到libxml2 必须修复 HTML 中的错误才能为其构建 DOM。这就是为什么&lt;html&gt;&lt;head&gt; 元素即使你没有指定它们也会出现的原因。您可以使用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        "
                
            ]
        
    ]

【讨论】:

非常感谢您的解决方案。我尝试了您对脚本标签的回答以及 html。它适用于所有 html 标签。但我的脚本部分出错。它甚至不适用于脚本标签。我尝试在 json2html 站点中使用脚本标记。我已经用预期的输出和脚本标签更新了我的问题。你能建议我解决方案吗? 我已经修改了答案以考虑具有CDATA 内容类型的元素。 你刚刚保存了我的皮肤。需要将原始 html 格式化为一组对象以转换为 pdf。想象一下手动解析它! 嗨@scozy,很好的答案。您能告诉我如何将相同的 JSON 格式转换回 Java(android 应用程序)中的 HTML 吗? 例如,如果您解析&lt;div&gt; xxx &lt;div&gt; yyy &lt;/div&gt; zzz &lt;/div&gt;xxx 将不会出现在 json 中,因为它将被zzz 覆盖,因为只有一个$obj["html"] on那个水平。我也将文本添加到孩子数组中,它就像一个魅力。谢谢!【参考方案2】:

我假设您的 html 字符串存储在 $html 变量中。所以你应该这样做:

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

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


$json = json_encode($result, JSON_UNESCAPED_UNICODE);

注意:该算法不支持父子标签,将所有标签作为父元素获取,并在排序队列中解析所有标签。当然,您可以通过研究DOMDocument 类功能来实现此功能。

【讨论】:

以上是关于如何使用 PHP 将 HTML 转换为 JSON?的主要内容,如果未能解决你的问题,请参考以下文章

如何使用 PHP 将 JSON 字符串数据转换为数组?

如何将php json数组转换为yaml

如何将 Csv 转换为 Json 并使用 Php 接收 Post?

如何将 JSON 转换为 SQL 查询 - php

如何将 json 编码的 PHP 数组转换为 Javascript 中的数组? [复制]

如何在php中正确的使用json(转)