Warning: file_get_contents(/data/phpspider/zhask/data//catemap/0/mercurial/2.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
Javascript PHPjQuery:将HTML从给定url转换为JSON,并创建HTML元素的树视图_Javascript_Php_Jquery_Html_Json - Fatal编程技术网

Javascript PHPjQuery:将HTML从给定url转换为JSON,并创建HTML元素的树视图

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="

基本上我有一个文本框,在这里我会输入URL并点击“确定按钮”,它会在页面左侧显示HTML预览;右侧将有一个HTML标记(body、header、div、span等)的树状视图,这些标记在HTML中用作附加图像。预期的JSON结果应该作为这个问题的结束。我无法遍历JSON并创建树。我尝试了以下方法:

HTML和JS代码:

<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>