为什么JSDOM会改变html结构?

问题描述 投票:0回答:1

这是代码

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文件之间的区别。为什么会改变?

javascript html jsdom
1个回答
1
投票

通常,将HTML序列化转换为DOM树,并序列化生成的树并不能保证最终的序列化与原始序列化完全相同。无论您的HTML是否符合规范,都是如此。

但是,在您的特定情况下,您的HTML不符合标准指定的结构。当符合标准的解析器遇到不符合的HTML时,它必须遵循一系列步骤来解决问题。这实际上是尝试在运行中理解不符合的HTML。在你的情况下,顺序是这样的:

  1. initial解析模式开始,
  2. 遇到before html时移动到DOCTYPE模式。
  3. 遇到before head时移动到<html>模式。
  4. 插入head元素并在遇到in head时移动到script

上面列举的最后一步是浏览器修改您的文档结构以使其符合。如果你检查规范中的rules,你会看到在script模式下遇到before head元素时匹配“Anything else”规则,这会导致将head元素附加到DOM树并移动到in head模式。然后在script模式中重新处理in head元素,并将其添加到新创建的head元素中。

当解析器运行到您放入HTML文件的<head>标记时,由于早期的in head元素,因此解析器已经处于script模式,因此忽略了此标记。


您获得的间距来自应用规范中的规则。指出一些突出的案例:

  1. <head>之前没有新行,因为before head模式中的任何空格都被忽略了。
  2. <head>之后没有新行,因为当解析器创建了一个head元素来修复HTML时,它没有插入换行符。 (这不是规则的一部分。)
  3. 您在序列化中在<title>之前看到的空白行由原始HTML中<head>之前和之后出现的换行符组成。解析器忽略了你的<head>标签(如上所述),但它保持了它周围的间距。
© www.soinside.com 2019 - 2024. All rights reserved.