Javascript PHPjQuery:将HTML从给定url转换为JSON,并创建HTML元素的树视图
基本上我有一个文本框,在这里我会输入URL并点击“确定按钮”,它会在页面左侧显示HTML预览;右侧将有一个HTML标记(body、header、div、span等)的树状视图,这些标记在HTML中用作附加图像。预期的JSON结果应该作为这个问题的结束。我无法遍历JSON并创建树。我尝试了以下方法: HTML和JS代码:Javascript PHPjQuery:将HTML从给定url转换为JSON,并创建HTML元素的树视图,javascript,php,jquery,html,json,Javascript,Php,Jquery,Html,Json,基本上我有一个文本框,在这里我会输入URL并点击“确定按钮”,它会在页面左侧显示HTML预览;右侧将有一个HTML标记(body、header、div、span等)的树状视图,这些标记在HTML中用作附加图像。预期的JSON结果应该作为这个问题的结束。我无法遍历JSON并创建树。我尝试了以下方法: HTML和JS代码: <html> <head> <meta charset="UTF-8"> <meta name="viewport" content="
<html>
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>ABC</title>
<link rel="stylesheet" type="text/css" href="css/main.css" />
</head>
<body>
<div id="wrapper">
<header>
<h1 class="logo"><img src="images/logo.png" alt="" title="" /></h1>
</header>
<div id="container">
<div class="search-box">
<input type="text" id="url" value="" class="txt-box" />
<input type="button" value="OK" class="btn-search" />
</div>
<div class="inner-wrap">
<div class="left-wrap" id="preview-sec">
</div>
<div class="right-wrap" id="tree-sec">
</div>
</div>
</div>
</div>
<script type="text/javascript" language="javascript" src="js/jquery-1.11.1.js"></script><!-- Jquery plugin -->
<script>
var counter = 0;
$(document).ready(function(){
$('.btn-search').click(function(){
if ($('#url').val() != '') {
$.get(
'http://localhost/test/getHTML.php', {url:$('#url').val()},
function(response) {
$('#preview-sec').html(response);
},'html');
$.getJSON('http://localhost/test/results.json', function(json) {
traverse(json,0);
});
}
});
});
function traverse(obj,id){
if (typeof(obj)=="object") {
if (id == 0) {
$('#tree-sec').append('<ul></ul>');
} else {
$(id).append('<ul></ul>');
}
$.each(obj, function(i,val){
if (i != 'attributes' && i != 'value') {
counter += 1;
var li_populate = "<li id="+i+"-"+counter+">"+i+"</li>";
if (id == 0) {
$('#tree-sec ul').append(li_populate);
} else {
$(id).find('ul').append(li_populate);
}
traverse(val,"#"+i+"-"+counter);
}
})
}
}
</script>
</body>
</html>
根据您的问题,遍历返回的json对象并创建树的部分是有问题的。在您的代码中,遍历json数据的递归函数在generate
ul
代码中有一些小问题。返回对象的结构使其具有一定的挑战性
我可以稍微修改一下你的html/javascript
代码(不做太多修改)以打印出树。相关代码如下:
CSS:
HTML&JS:
...
...
<div class="inner-wrap">
<div class="left-wrap" id="preview-sec">
<iframe id="preview"></iframe>
</div>
<div class="right-wrap" id="tree-sec">
<ul id="treehtml1"></ul>
</div>
</div>
....
....
<script type="text/javascript">
var counter = 0;
$(document).ready(function(){
$('.btn-search').click(function(){
if ($('#url').val() != '') {
$.get('http://localhost/test/getHTML.php', {url:$('#url').val()}, function(response) {
$('#preview-sec').html(response);
},'html');
$.getJSON('http://localhost/test/results.json', function(json) {
if(typeof(json) == "object"){
traverse(json,'html',1);
makeCollapsible();
}
});
}
});
});
function traverse(obj, element, counter){
for (var i in obj){
$("#tree"+element+counter).append("<li id='"+i+counter+"'>"+i+"</li>"); // Add element to the tree
if(obj[i].hasOwnProperty('child_nodes')){
$("#"+i+counter).append("<ul id='tree"+i+(counter+1)+"'></ul>"); // If there are children, add a parent ul and pass the name to subsequent recursive calls for each child
for(var j in obj[i].child_nodes){
traverse(obj[i].child_nodes[j], i, counter + 1); // Recursive call to add child
}
}
}
}
function makeCollapsible(){
$('ul.parent').each(function(i) {
var parent_li = $(this).parent('li');
parent_li.addClass('collapsible'); //Use this selector to style your parent items...
// Temporarily remove the list from the
// parent list item, wrap the remaining
// text in an anchor, then reattach it.
var sub_ul = $(this).remove();
parent_li.wrapInner('<a/>').children('a').click(function() {
// Toggle the children...
sub_ul.toggle();
});
parent_li.append(sub_ul);
});
// Hide all lists except the outermost.
$('ul ul').hide();
}
</script>
....
....
。。。
...
....
....
var计数器=0;
$(文档).ready(函数(){
$('.btn search')。单击(函数(){
if($('#url').val()!=''){
$.get('http://localhost/test/getHTML.php“,{url:$('#url').val()},函数(响应){
$(“#预览第二节”).html(响应);
},'html');
$.getJSON('http://localhost/test/results.json,函数(json){
if(typeof(json)=“object”){
遍历(json,'html',1);
使可折叠();
}
});
}
});
});
功能遍历(对象、元素、计数器){
用于(obj中的var i){
$(“#tree”+元素+计数器)。追加(““+i+” ”);//将元素添加到树中
if(obj[i].hasOwnProperty('child_nodes')){
$(“#”+i+计数器)。追加(“
另外,我想提到的另一件事是,我建议您使用
iframe
,而不是将检索到的html加载到div中,因为检索到的html不会干扰当前页面。在我上面的示例中,我在预览div
中添加了iframe
。在这种情况下,您可以使用php只输出json
数据,并设置iframe
预览url,只需将url指定为iframe
的src
属性即可
编辑:
更新了带有修复程序的代码。还添加了一个新的js函数makecollapsable()
,以根据OP的评论将ul
反向转换为可点击的可折叠树结构。还添加了相关的CSS
样式来设置树结构的样式。树现在看起来像下图:
看看这是杰克写的
希望对您有所帮助。附录:这是一个很长的答案,但它解决了您提供的代码片段的具体问题和解决方案。我希望您和其他人会觉得值得花时间进行比较。:)
首先,修改PHP以使JSON更干净
解析DOM时,我建议使用array\u merge()
将返回对象中的元素名设置为$arr['child\u nodes']
中的关联键,而不是将它们作为索引项推送到数组中。为此,$arr['child\u nodes']
必须首先定义为数组。之后,如果没有项目合并到其中,只需在将$arr
添加到主对象之前取消设置它即可
这使得最终的JSON结果更易于解析,因为在构建树时不需要在javascript中使用嵌套循环
我还建议在执行foreach
循环之前插入->length
的条件检查。当长度为零的元素进入循环时,现有代码会抛出“警告”消息
最后,您可以选择简化处理节点类型的逻辑,将当前的if、else-if、else
语句替换为单个if
检查$subElement->nodeType===XML\u ELEMENT\u node
,我认为这正是您试图实现的
<?php
$url = $_GET['url'];
$html = file_get_contents($url);
function html_to_obj($html) {
$dom = new DOMDocument();
$dom->loadHTML($html);
return element_to_obj($dom->documentElement);
}
function element_to_obj($element) {
$obj = $attr = $arr = array();
$name = $element->tagName;
if ($element->attributes->length) {
foreach ($element->attributes as $attribute) {
$attr[$attribute->name] = $attribute->value;
if ($attribute->name == 'id') {
$name .= '#'.$attribute->value;
}
}
}
if (!empty($attr)) {
$arr["attributes"] = $attr;
}
if ($element->nodeValue != '') {
$arr["value"] = $element->nodeValue;
}
if ($element->childNodes->length) {
$arr["child_nodes"] = array();
foreach ($element->childNodes as $subElement) {
if ($subElement->nodeType === XML_ELEMENT_NODE) {
$arr["child_nodes"] = array_merge($arr["child_nodes"], element_to_obj($subElement));
}
}
if (!count($arr["child_nodes"])) {
unset($arr["child_nodes"]);
}
}
$obj[$name] = $arr;
return $obj;
}
$json = json_encode(html_to_obj($html));
$fp = fopen('results.json', 'w');
fwrite($fp, $json);
fclose($fp);
?>
好处:在CSS中使用属性选择器
最后,如上所述,aria-
和role
属性的存在为控制样式提供了语义和方便的方法
ul[role='tree'] {
margin-left: 1em;
padding-left: 0;
}
ul[role='tree'] li {
cursor: default;
margin: 0;
padding: 0 0 0 20px;
font: normal 1em sans-serif;
color: #333;
}
ul[role='tree'] li[aria-expanded] {
cursor: pointer;
font-weight: bold;
color: #111;
background: transparent 0 0 no-repeat url('images/arrow-sprite.png');
}
ul[role='tree'] li[aria-expanded="true"] {
background-position: 0 0;
}
ul[role='tree'] li[aria-expanded="false"] {
background-position: 0 20px;
}
看看XSLT处理,它可以用更少的代码工作
<?xml version="1.0"?>
<?xml-stylesheet type="text/xsl" href="json.xml"?>
<html>
<body>
<h1>title</h1>
<h2>title 2</h2>
<h3>title 3</h3>
<ul>
<li>t1</li>
<li>t2</li>
<li>t3</li>
</ul>
</body>
</html>
<?xml version="1.0"?>
<xsl:stylesheet version="1.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform">
<xsl:output method="text"/>
<xsl:template name="json" match="/">
<xsl:for-each select="*">
{"<xsl:value-of select="local-name()"/>": "<xsl:if test="count(*)=0"><xsl:value-of select="text()"/></xsl:if>",
"attributes": {<xsl:for-each select="@*"><xsl:if test="position()>1">,</xsl:if>"<xsl:value-of select="local-name()"/>": "<xsl:value-of select="text()"/>"</xsl:for-each>},<xsl:call-template name="json"/>}</xsl:for-each>
</xsl:template>
</xsl:stylesheet>
标题
标题2
标题3
- t1
- t2
- t3
{"": "",
“属性”:{,“:”“},}
为HTML标记构造多维PHP数组,然后将该数组作为PHP内置函数json_encode($array)的输入,这将返回树结构的json输出您实际上是在尝试创建树的图像还是
<?php
$url = $_GET['url'];
$html = file_get_contents($url);
function html_to_obj($html) {
$dom = new DOMDocument();
$dom->loadHTML($html);
return element_to_obj($dom->documentElement);
}
function element_to_obj($element) {
$obj = $attr = $arr = array();
$name = $element->tagName;
if ($element->attributes->length) {
foreach ($element->attributes as $attribute) {
$attr[$attribute->name] = $attribute->value;
if ($attribute->name == 'id') {
$name .= '#'.$attribute->value;
}
}
}
if (!empty($attr)) {
$arr["attributes"] = $attr;
}
if ($element->nodeValue != '') {
$arr["value"] = $element->nodeValue;
}
if ($element->childNodes->length) {
$arr["child_nodes"] = array();
foreach ($element->childNodes as $subElement) {
if ($subElement->nodeType === XML_ELEMENT_NODE) {
$arr["child_nodes"] = array_merge($arr["child_nodes"], element_to_obj($subElement));
}
}
if (!count($arr["child_nodes"])) {
unset($arr["child_nodes"]);
}
}
$obj[$name] = $arr;
return $obj;
}
$json = json_encode(html_to_obj($html));
$fp = fopen('results.json', 'w');
fwrite($fp, $json);
fclose($fp);
?>
<div class="inner-wrap">
<div class="left-wrap" id="preview-sec">
<iframe src=""></iframe>
</div>
<div class="right-wrap" id="tree-sec">
</div>
</div>
$(document).ready(function () {
function traverse(data, firstTime) {
if (typeof data === 'object') {
var ul = '<ul role="' + (firstTime ? 'tree' : 'group' ) + '">';
$.each(data, function (key, val) {
if (key !== 'attributes' && key !== 'value') {
if (val['child_nodes']) {
ul += '<li aria-expanded="true" role="tree-item" tabindex="0">';
ul += key;
ul += traverse(val['child_nodes']);
ul += '</li>';
} else {
ul += '<li role="tree-item" tabindex="0">';
ul += key;
ul += '</li>';
}
}
});
ul += '</ul>';
return ul;
}
}
$('.btn-search').on('click', function () {
var url = $('#url').val();
if (url) {
$.get(
'getHTML.php',
{
url: url
},
function () {
$('#preview-sec iframe').attr('src', url);
$('#tree-sec').empty();
$.get(
'results.json',
function (json) {
$('#tree-sec').append(traverse(json, true));
},
'json'
);
},
'html'
);
}
});
$('#tree-sec').on('click', 'li[aria-expanded]', function (e) {
e.stopPropagation();
$(this)
.attr('aria-expanded', function (i, attr) {
return !(attr === 'true');
})
.children('ul')
.attr('aria-hidden', function (i, attr) {
return !(attr === 'true');
})
.toggle();
});
});
ul[role='tree'] {
margin-left: 1em;
padding-left: 0;
}
ul[role='tree'] li {
cursor: default;
margin: 0;
padding: 0 0 0 20px;
font: normal 1em sans-serif;
color: #333;
}
ul[role='tree'] li[aria-expanded] {
cursor: pointer;
font-weight: bold;
color: #111;
background: transparent 0 0 no-repeat url('images/arrow-sprite.png');
}
ul[role='tree'] li[aria-expanded="true"] {
background-position: 0 0;
}
ul[role='tree'] li[aria-expanded="false"] {
background-position: 0 20px;
}
<?xml version="1.0"?>
<?xml-stylesheet type="text/xsl" href="json.xml"?>
<html>
<body>
<h1>title</h1>
<h2>title 2</h2>
<h3>title 3</h3>
<ul>
<li>t1</li>
<li>t2</li>
<li>t3</li>
</ul>
</body>
</html>
<?xml version="1.0"?>
<xsl:stylesheet version="1.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform">
<xsl:output method="text"/>
<xsl:template name="json" match="/">
<xsl:for-each select="*">
{"<xsl:value-of select="local-name()"/>": "<xsl:if test="count(*)=0"><xsl:value-of select="text()"/></xsl:if>",
"attributes": {<xsl:for-each select="@*"><xsl:if test="position()>1">,</xsl:if>"<xsl:value-of select="local-name()"/>": "<xsl:value-of select="text()"/>"</xsl:for-each>},<xsl:call-template name="json"/>}</xsl:for-each>
</xsl:template>
</xsl:stylesheet>