如何使用 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->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
对象。这是因为 PHP 中的 DOM 扩展基于 libxml2
,,它将您的 HTML 解析为 HTML 4.0,而在 HTML 4.0 中,<script>
的内容类型为 CDATA
而不是 #PCDATA
。
对于这个问题,你有两个解决方案。
简单但不太健壮的解决方案是将LIBXML_NOCDATA
标志添加到DOMDocument::loadHTML
.(我实际上并不能100% 确定这是否适用于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
的类型,因为存在many other possibilities,我的简短示例函数没有处理。
此外,您会注意到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 "
]
]
【讨论】:
非常感谢您的解决方案。我尝试了您对脚本标签的回答以及 html。它适用于所有 html 标签。但我的脚本部分出错。它甚至不适用于脚本标签。我尝试在 json2html 站点中使用脚本标记。我已经用预期的输出和脚本标签更新了我的问题。你能建议我解决方案吗? 我已经修改了答案以考虑具有CDATA
内容类型的元素。
你刚刚保存了我的皮肤。需要将原始 html 格式化为一组对象以转换为 pdf。想象一下手动解析它!
嗨@scozy,很好的答案。您能告诉我如何将相同的 JSON 格式转换回 Java(android 应用程序)中的 HTML 吗?
例如,如果您解析<div> xxx <div> yyy </div> zzz </div>
,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?的主要内容,如果未能解决你的问题,请参考以下文章
如何将 Csv 转换为 Json 并使用 Php 接收 Post?