2017-12-27 448 views
0

下面是代碼爲什麼JSDOM更改html結構?

var fs = require('fs') 
var htmlSource = fs.readFileSync("public/html/index.html", "utf8") 
var jsdom = require('jsdom'); 
const {JSDOM} = jsdom; 
const dom = new JSDOM(htmlSource); 
htmlSource = dom.window.document.querySelector("html").outerHTML 
console.log(htmlSource) 
<!-- This is a public/html/index.html --> 
<!DOCTYPE html> 
<html> 
<script src="https://ajax.googleapis.com/ajax/libs/jquery/3.2.1/jquery.min.js"></script> 
<script src="https://ajax.googleapis.com/ajax/libs/angularjs/1.6.4/angular.min.js"></script> 
<script type="text/javascript" src="js/main.js"></script> 
<head> 
    <title>Home Electricity Manager</title> 
</head> 
<body ng-app="myApp"> 
    <h1 id="the-header">Wellcome to home electricity manager!</h1> 
    <div add-row ng-controller="myController" style="text-align: center; display: inline-block;"> 
     <span style="white-space:pre;">Button text</span><br/> 
     <button id="first-button" ng-style="myStyle" ng-click="toggleRelay()" id="switch-cirquit-1">{{ButtonStatus}}</button> 
    </div> 
    <div add-row ng-controller="myController" style="text-align: center; display: inline-block;"> 
     <span id="second-button" style="white-space:pre;">{{buttonOneText}}</span><br/> 
     <button ng-style="myStyle" ng-click="toggleRelay()" id="switch-cirquit-1">{{ButtonStatus}}</button> 
    </div> 
    <div ng-controller="postController" style="text-align: center; display: inline-block;"> 
     <button ng-click="post()">{{buttonName}}</button> 
    </div> 
</body> 
</html> 

<!-- src="js/directives/add-row.js" --> 

而結果形成線console.log(htmlSource)是:

<html><head><script src="https://ajax.googleapis.com/ajax/libs/jquery/3.2.1/jquery.min.js"></script> 
<script src="https://ajax.googleapis.com/ajax/libs/angularjs/1.6.4/angular.min.js"></script> 
<script type="text/javascript" src="js/main.js"></script> 

    <title>Home Electricity Manager</title> 
</head> 
<body ng-app="myApp"> 
    <h1 id="the-header">Wellcome to home electricity manager!</h1> 
    <div add-row="" ng-controller="myController" style="text-align: center; display: inline-block;"> 
     <span style="white-space:pre;">Button text</span><br> 
     <button id="first-button" ng-style="myStyle" ng-click="toggleRelay()">{{ButtonStatus}}</button> 
    </div> 
    <div add-row="" ng-controller="myController" style="text-align: center; display: inline-block;">  
     <span id="second-button" style="white-space:pre;">{{buttonOneText}}</span><br> 
     <button ng-style="myStyle" ng-click="toggleRelay()" id="switch-cirquit-1">{{ButtonStatus}}</button> 
    </div> 
    <div ng-controller="postController" style="text-align: center; display: inline-block;"> 
     <button ng-click="post()">{{buttonName}}</button> 
    </div> 



</body></html> 

請注意,script元素從<html>孩子移居到了<head>兒童。這是自動發生的。此外,一些新的行似乎被添加到新創建的dom文件。請看兩個html文件的區別。爲什麼是這種變化?

+1

每規範,允許作爲一個'html'元素的直接孩子的唯一標籤是'head'和'body'。 – Amy

+1

''裏面html' script'是無效的HTML。 – Claies

+1

這是無效的HTML有腳本漂浮作爲''直接孩子。它可能會做一些簡單的驗證檢查,例如爲指令屬性添加空值。 – Phix

回答

1

一般而言,轉動一個HTML串行化爲一個DOM樹,和序列化所得到的樹將不能保證最終序列將是相同的原來的一個。無論您的HTML是否符合規範,都是如此。

但是,在您的具體情況下,您的HTML不符合標準指定的結構。當一致性解析器遇到不合格的HTML時,它必須遵循一系列步驟來解決問題。這實際上是嘗試瞭解運行中不符合要求的HTML。在你的情況下的流程是這樣的:

  1. 開始在initial解析模式,遇到DOCTYPE
  2. 移動到before html模式。
  3. 當遇到<html>時,移至before head模式。
  4. 插入head元素,並在遇到script時移至in head

上面列舉的最後一步是在瀏覽器中修改文檔結構,使其符合。如果您在規範中檢查rules,您會發現在before head模式中遇到script元素時,會匹配「其他」規則,從而導致將head元素附加到DOM樹並移至in head模式。 script元素然後在in head模式中重新處理,並且僅添加到新創建的head元素中。

當分析器跑進<head>標籤你把你的HTML文件中,這個標籤只是忽略,因爲解析器已經在in head模式,由於較早script元素。


您得到的間距是應用規範中的規則。要指出的幾個突出的案例:

  1. <head>前不換行,因爲before head模式的任何空間將被忽略。
  2. <head>之後沒有新行,因爲當解析器創建了一個head元素來修復您的HTML時,它沒有插入換行符。(這只是不是規則的一部分。)
  3. <title>之前看到的空行的序列化是在原始的HTML由這似乎與之前的新行後<head>。解析器忽略了你的<head>標籤(如上所述),但它一直這是周圍的間距。