提问人:Ancy 提问时间:11/4/2022 最后编辑:Sebastian SimonAncy 更新时间:11/5/2022 访问量:90
需要检查XML中是否存在处理指令“<covid19?>”
Need to check if processing instruction `<?covid19?>` is present in XML or not
问:
<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE article PUBLIC "-//NLM//DTD JATS (Z39.96) Journal Publishing DTD v1.1d1 20130915//EN" "JATS-journalpublishing1.dtd"[]>
<article dtd-version="1.1d1" article-type="review-article" xmlns:xlink="http://www.w3.org/1999/xlink" xmlns:mml="http://www.w3.org/1998/Math/MathML" xml:lang="en">
<front>
<?covid19?>
我需要确定处理指令是否存在于 XML 中。<?covid19?>
jQuery中的伪代码:
$("<?covid19?>").length
答:
虽然没有 CSS 选择器来选择元素等处理指令,但您可以使用两个不错的 API 来避免手动迭代 DOM 树。
假设您的 XML 文档是 XMLDocument
;您可以通过使用 DOMParser
API 解析 XML 字符串来创建一个:theDocument
const xml = `<?xml version="1.0" encoding="UTF-8"?>
<root>
<?covid19 content-a?>
<?covid19 content-b?>
<?thing x?>
<child>
<?covid19 content-c?>
<?thing y?>
</child>
<covid19>
Reject this node.
</covid19>
</root>`,
theDocument = new DOMParser().parseFromString(xml, "text/xml");
NodeIterator
应用程序接口
使用 NodeIterator API(使用 theDocument.createNodeIterator
)可以查找所有处理指令。
const iteratorAll = theDocument
.createNodeIterator(theDocument, NodeFilter.SHOW_PROCESSING_INSTRUCTION);
const iteratorCOVID19 = theDocument
.createNodeIterator(theDocument, NodeFilter.SHOW_PROCESSING_INSTRUCTION, {
acceptNode(node){
if(node.nodeName.toLowerCase() === "covid19"){
return NodeFilter.FILTER_ACCEPT;
}
return NodeFilter.FILTER_SKIP;
}
});
iteratorAll
是显示所有处理指令的 a。 是显示所有带有名称的处理指令的 。NodeIterator
iteratorCOVID19
NodeIterator
covid19
TreeWalker API(使用 theDocument.createTreeWalker
)与 API 非常相似。
NodeIterator
XPath 迭代器 API
也可以使用 XPath(使用 theDocument.evaluate
)查找所有处理指令。
结果是 XPathResult
s。
const xPathAll = theDocument
.evaluate("//processing-instruction()", theDocument, null, XPathResult.ORDERED_NODE_ITERATOR_TYPE);
const xPathCOVID19 = theDocument
.evaluate("//processing-instruction('covid19')", theDocument, null, XPathResult.ORDERED_NODE_ITERATOR_TYPE);
XPath 语法说明:
令 牌 | 意义 |
---|---|
// |
获取所有后代 |
processing-instruction() |
获取“处理指令”类型的节点 |
processing-instruction('covid19') |
获取类型为“processing instruction”的节点,其名称为covid19 |
该XPathResult.ORDERED_NODE_ITERATOR_TYPE
可用于确保按文档顺序返回节点。
xPathAll
是一个迭代器,它显示所有处理指令。 是一个迭代器,它显示所有带有 名称的处理指令。XPathResult
xPathCOVID19
XPathResult
covid19
迭代帮助程序
这两个 API 在浏览器支持方面非常出色,但这意味着它们已经足够老了,以至于它们没有现代迭代协议。 但这就是发电机被证明有用的地方。
此代码定义了生成器函数,该函数将完全消耗任一迭代器找到的所有节点。
由于 API 获取下一个结果的方法称为 nextNode
,而 XPath 方法称为 iterateNext
,因此此函数会检查要使用的方法名称中的哪个。
如果找不到适当的方法,它将遵循默认的迭代协议。
然后,一个简单的循环重复调用这些方法之一并产生
它们,直到返回为止。consumeDOMIterator
NodeIterator
while
null
function* consumeDOMIterator(iterator){
const method = (iterator instanceof NodeIterator || iterator instanceof TreeWalker
? "nextNode"
: iterator instanceof XPathResult && [
XPathResult.UNORDERED_NODE_ITERATOR_TYPE,
XPathResult.ORDERED_NODE_ITERATOR_TYPE
].includes(iterator.resultType)
? "iterateNext"
: null);
if(!method){
yield* iterator[Symbol.iterator]();
return;
}
let node;
while((node = iterator[method]())){
yield node;
}
}
现在,该函数可用于从迭代器创建 Array。Array.from
可以很容易地实现这一点:
Array.from(consumeDOMIterator(iteratorCOVID19))
// Or any of these:
Array.from(consumeDOMIterator(xPathCOVID19))
Array.from(consumeDOMIterator(iteratorAll))
Array.from(consumeDOMIterator(xPathAll))
要检查处理指令是否存在,只需检查 Array 的 or if 或返回 .length
iteratorCOVID19.nextNode()
xPathCOVID19.iterateNext()
Node
请注意,它的名称是有原因的:一旦您开始使用此函数遍历 API 结果以创建 Array,结果的状态就会发生变化。
到达末尾后,任一迭代器都将位于文档的“末尾”,因此没有下一个节点。
虽然 API 具有 previousNode
,但 XPath Iterator API 没有相应的方法;一般来说,迭代器只能迭代一次。consume
NodeIterator
XPath 快照 API
或者,可用于获得更直接的结果集,这些结果可以更容易地迭代。XPathResult.ORDERED_NODE_SNAPSHOT_TYPE
const snapshotAll = theDocument
.evaluate("//processing-instruction()", theDocument, null, XPathResult.ORDERED_NODE_SNAPSHOT_TYPE);
const snapshotCOVID19 = theDocument
.evaluate("//processing-instruction('covid19')", theDocument, null, XPathResult.ORDERED_NODE_SNAPSHOT_TYPE);
现在,由于 是一个快照,因此可以使用 snapshotLength
来获取所有 snapshotItem
。
同样,可用于轻松实现此目的:XPathResult
Array.from
Array.from({
length: snapshotCOVID19.snapshotLength
}, (_, index) => snapshotCOVID19.snapshotItem(index));
与迭代器方法的唯一区别是,当基础文档发生突变时,迭代器不会更改。XPathResult
要检查处理指令是否存在,只需检查 Array 的 or if 返回 .length
snapshotCOVID19.snapshotItem(0)
Node
完整代码
此代码片段完整演示了如何获取表单的所有处理指令,例如,获取其:<?covid19?>
nodeValue
function* consumeDOMIterator(iterator){
const method = (iterator instanceof NodeIterator || iterator instanceof TreeWalker
? "nextNode"
: iterator instanceof XPathResult && [
XPathResult.UNORDERED_NODE_ITERATOR_TYPE,
XPathResult.ORDERED_NODE_ITERATOR_TYPE
].includes(iterator.resultType)
? "iterateNext"
: null);
if(!method){
yield* iterator[Symbol.iterator]();
return;
}
let node;
while((node = iterator[method]())){
yield node;
}
}
const xml = `<?xml version="1.0" encoding="UTF-8"?>
<root>
<?covid19 content-a?>
<?covid19 content-b?>
<?thing x?>
<child>
<?covid19 content-c?>
<?thing y?>
</child>
<covid19>
Reject this node.
</covid19>
</root>`,
theDocument = new DOMParser().parseFromString(xml, "text/xml"),
iteratorAll = theDocument
.createNodeIterator(theDocument, NodeFilter.SHOW_PROCESSING_INSTRUCTION),
iteratorCOVID19 = theDocument
.createNodeIterator(theDocument, NodeFilter.SHOW_PROCESSING_INSTRUCTION, {
acceptNode(node){
if(node.nodeName.toLowerCase() === "covid19"){
return NodeFilter.FILTER_ACCEPT;
}
return NodeFilter.FILTER_SKIP;
}
}),
xPathAll = theDocument
.evaluate("//processing-instruction()", theDocument, null, XPathResult.ORDERED_NODE_ITERATOR_TYPE),
xPathCOVID19 = theDocument
.evaluate("//processing-instruction('covid19')", theDocument, null, XPathResult.ORDERED_NODE_ITERATOR_TYPE),
snapshotAll = theDocument
.evaluate("//processing-instruction()", theDocument, null, XPathResult.ORDERED_NODE_SNAPSHOT_TYPE),
snapshotCOVID19 = theDocument
.evaluate("//processing-instruction('covid19')", theDocument, null, XPathResult.ORDERED_NODE_SNAPSHOT_TYPE);
const demoIterator = (iterator) => Array.from(consumeDOMIterator(iterator), ({ nodeName, nodeValue }) => [
nodeName,
nodeValue
]);
const demoIterator2 = (iterator) => Array.from(consumeDOMIterator(iterator), ({ nodeValue }) => nodeValue);
console.log("All PIs using NodeIterator", demoIterator(iteratorAll));
console.log("All PIs using XPath Iterator", demoIterator(xPathAll));
console.log("All PIs using XPath Snapshot", Array.from({
length: snapshotAll.snapshotLength
}, (_, index) => {
const {
nodeName,
nodeValue
} = snapshotAll.snapshotItem(index);
return [
nodeName,
nodeValue
];
}));
console.log("All node values of <?covid19?> PIs using NodeIterator", demoIterator2(iteratorCOVID19));
console.log("All node values of <?covid19?> PIs using XPath Iterator", demoIterator2(xPathCOVID19));
console.log("All node values of <?covid19?> PIs using XPath Snapshot", Array.from({
length: snapshotCOVID19.snapshotLength
}, (_, index) => snapshotCOVID19.snapshotItem(index).nodeValue));
.as-console-wrapper { max-height: 100% !important; top: 0; }
评论
TreeWalker
API 来查找此处理指令。