JSDOM 的 querySelectorAll 返回了太多 XML 个元素
JSDOM's querySelectorAll returned too many XML elements
Node.js版本:10.15.3
jsdom 版本:15.1.0
const fs = require('fs');
const jsdom = require("jsdom");
const { JSDOM } = jsdom;
const xmlFile = fs.readFileSync("question.xml", "utf8");
const dom = new JSDOM(xmlFile);
const all = dom.window.document.querySelectorAll("S");
console.log(all);
<?xml version="1.0" encoding="utf-8"?>
<Foo>
<FooBar>
<S a="string1" b="string2" c="string3"/>
</FooBar>
</Foo>
<Foo>
<FooBar>
<S a="string1" b="string2"/>
<S a="string1"/>
</FooBar>
</Foo>
querySelectorAll("S")
returns 7 个 HTML 元素,而显然只有 3 个元素。更奇怪的是,如果我将 xml 元素重命名为 S
到 F
,它工作正常并且 querySelectorAll("F")
只找到 3 个元素。这种不一致的原因是什么?
默认情况下,JSDOM 将您提供给它的标记解释为 HTML。因此它将您的 XML 解释为 HTML,您会得到奇怪的结果。请记住,HTML 规范提供了有关如何理解损坏的 HTML 的规则,因此当 JSDOM 读取您的 XML 时,它会应用这些规则并尝试从中获取一些合理的文档。如果我拿走你的 XML 和你的代码,但我添加
console.log(dom.window.document.documentElement.innerHTML);
就在分配 dom
的行之后,我将其序列化 HTML:
<head></head><body><foo>
<foobar>
<s a="string1" b="string2" c="string3">
</s></foobar><s a="string1" b="string2" c="string3">
</s></foo><s a="string1" b="string2" c="string3">
<foo>
<foobar>
<s a="string1" b="string2">
<s a="string1">
</s></s></foobar><s a="string1" b="string2"><s a="string1">
</s></s></foo><s a="string1" b="string2"><s a="string1">
</s></s></s></body>
看看 s
会发生什么。 (提醒:HTML 元素名称是 case-insensitive 所以 S
和 s
是相同的 HTML 元素。)
顺便说一下,S
与 F
不同的原因是因为 S
是 actual HTML element,而 F
不是。因此,当 JSDOM 试图将您的文档理解为 HTML.
时,它对 S
应用的规则不同于 F
为了让 JSDOM 将您的文档解释为 XML,您可以这样做:
const dom = new JSDOM(xmlFile, { contentType: "text/xml" });
但请注意,您的文档不是 well-formed XML,因为它有多个根元素。 XML 规范没有提供任何规则来理解非 well-formed 的文档。不是 well-formed 的文档本质上不是 XML。所以 JSDOM 只会拒绝你的文档。您需要对其进行编辑,使其只有一个根元素。例如,这会起作用:
<?xml version="1.0" encoding="utf-8"?>
<doc>
<Foo>
<FooBar>
<S a="string1" b="string2" c="string3"/>
</FooBar>
</Foo>
<Foo>
<FooBar>
<S a="string1" b="string2"/>
<S a="string1"/>
</FooBar>
</Foo>
</doc>
我刚刚将两个 Foo
元素包装在一个 doc
元素中,该元素形成 XML.
所需的单个根
Node.js版本:10.15.3 jsdom 版本:15.1.0
const fs = require('fs');
const jsdom = require("jsdom");
const { JSDOM } = jsdom;
const xmlFile = fs.readFileSync("question.xml", "utf8");
const dom = new JSDOM(xmlFile);
const all = dom.window.document.querySelectorAll("S");
console.log(all);
<?xml version="1.0" encoding="utf-8"?>
<Foo>
<FooBar>
<S a="string1" b="string2" c="string3"/>
</FooBar>
</Foo>
<Foo>
<FooBar>
<S a="string1" b="string2"/>
<S a="string1"/>
</FooBar>
</Foo>
querySelectorAll("S")
returns 7 个 HTML 元素,而显然只有 3 个元素。更奇怪的是,如果我将 xml 元素重命名为 S
到 F
,它工作正常并且 querySelectorAll("F")
只找到 3 个元素。这种不一致的原因是什么?
默认情况下,JSDOM 将您提供给它的标记解释为 HTML。因此它将您的 XML 解释为 HTML,您会得到奇怪的结果。请记住,HTML 规范提供了有关如何理解损坏的 HTML 的规则,因此当 JSDOM 读取您的 XML 时,它会应用这些规则并尝试从中获取一些合理的文档。如果我拿走你的 XML 和你的代码,但我添加
console.log(dom.window.document.documentElement.innerHTML);
就在分配 dom
的行之后,我将其序列化 HTML:
<head></head><body><foo>
<foobar>
<s a="string1" b="string2" c="string3">
</s></foobar><s a="string1" b="string2" c="string3">
</s></foo><s a="string1" b="string2" c="string3">
<foo>
<foobar>
<s a="string1" b="string2">
<s a="string1">
</s></s></foobar><s a="string1" b="string2"><s a="string1">
</s></s></foo><s a="string1" b="string2"><s a="string1">
</s></s></s></body>
看看 s
会发生什么。 (提醒:HTML 元素名称是 case-insensitive 所以 S
和 s
是相同的 HTML 元素。)
顺便说一下,S
与 F
不同的原因是因为 S
是 actual HTML element,而 F
不是。因此,当 JSDOM 试图将您的文档理解为 HTML.
S
应用的规则不同于 F
为了让 JSDOM 将您的文档解释为 XML,您可以这样做:
const dom = new JSDOM(xmlFile, { contentType: "text/xml" });
但请注意,您的文档不是 well-formed XML,因为它有多个根元素。 XML 规范没有提供任何规则来理解非 well-formed 的文档。不是 well-formed 的文档本质上不是 XML。所以 JSDOM 只会拒绝你的文档。您需要对其进行编辑,使其只有一个根元素。例如,这会起作用:
<?xml version="1.0" encoding="utf-8"?>
<doc>
<Foo>
<FooBar>
<S a="string1" b="string2" c="string3"/>
</FooBar>
</Foo>
<Foo>
<FooBar>
<S a="string1" b="string2"/>
<S a="string1"/>
</FooBar>
</Foo>
</doc>
我刚刚将两个 Foo
元素包装在一个 doc
元素中,该元素形成 XML.