XPath和XQuery可以在HTML文档上工作吗?

时间:2019-04-23 22:18:47

标签: html xml web xpath xquery

我听说https://stackoverflow.com/a/39560454中的HTML文档不是XML文档。

XPath和XQuery可处理XML文档。它们可以处理HTML文档吗?为什么?

尽管我不知道为什么,但是我猜XPath可以在HTML文档上使用,因为https://www.quora.com/Why-do-we-use-XPath-in-Selenium-even-though-CSS-Selector-is-fasterhttps://html-agility-pack.net/

(如果我也要问的话,是推荐它们在HTML文档上使用的推荐工具,还是推荐一些替代工具?如果不能,请忽略。)

谢谢。

5 个答案:

答案 0 :(得分:6)

XQuery和XPath被定义为在称为XDM的特定数据模型上工作。在XPath 1.0中,这在XPath规范中进行了描述。在XQuery和更高版本的XPath中,它是在单独的规范中定义的。 XPath和XQuery可以在定义了XDM映射的任何数据上使用。 XML和HTML DOM在细节上与XDM都不同,但是可以(有点实用主义)定义到XDM的映射,因此XPath可以同时针对XML和HTML DOM运行。的确,尽管这两种映射不完善且在某些情况下效率不高,但它们的使用非常广泛。

HTML映射到XDM的最大问题是名称空间。传统上,XPath实现将HTML元素(例如“ table”和“ p”)视为没有命名空间,因此可以使用诸如//table//p之类的路径而无需命名空间前缀。但是在HTML5中,WhatWG决定这些元素在XHTML命名空间中,这意味着它们必须定义XPath规范的变体以容纳此类路径。

CSS选择器已经慢慢获得了XPath 1.0的大部分表达能力,尽管它们肯定不如后来的版本丰富,并且由于它们主要是为HTML而不是XML设计的,因此有时使用起来更方便。我还没有看到任何性能数据,但是浏览器供应商必须付出很大的努力来使CSS更快,并且在过去的15年中,他们似乎在XPath实现上进行了几乎为零的开发,因此肯定不会。如果CSS在大多数浏览器中速度更快,我不会感到惊讶。 DOM和XDM之间的差异也会造成开销:值得注意的是,DOM中名称空间的表示效率非常低。

答案 1 :(得分:2)

HTML不能保证格式正确,因此XML解析器可能无法解析它(除非您使用的HTML子集非常有限)。但是,XHTML是HTML的格式良好的表亲,据我所知,它可以在具有相同功能集的浏览器中使用(请参阅:https://www.w3.org/TR/html-polyglot/)。

但是,如果您已经拥有HTML,则需要将其转换为XML以使用XPath / XQuery。有“ HTML tidy”的各种实现,可以选择输出有效的XML。 XQuery处理器中可能提供了某种整洁的形式。如果没有,那么可能有许多语言和独立的实现方式可以帮助您到达目的地。

答案 2 :(得分:2)

EXPath W3C社区有一个HTTP客户端模块的规范,该模块可从XPath和XQuery实现中访问,该实现执行HTML内容的“整理”。有关描述此内容的规范部分,请参见http://expath.org/spec/http-client#d2e517

  

如果媒体类型是HTML类型,则将整理内容并进行解析(此过程取决于实现),并且该项目是结果文档节点。

现在,您可能认为将HTTP纳入查询HTML的问题有点a回,但是很自然地,人们可能想查询或遍历通过HTTP检索的HTML文档。它也符合不依赖于处理器的精神。

以下代码示例是标准XQuery,可在任何支持EXPath HTTP Client的XPath或XQuery实现上使用。它演示了如何检索HTML5文档(此处为HTML5规范本身,其未封闭的标签(如<meta>使其格式不正确的XML)并通过XPath表达式进行查询:

xquery version "3.1";

declare namespace html = "http://www.w3.org/1999/xhtml";

import module namespace http = "http://expath.org/ns/http-client";

let $url := "https://www.w3.org/TR/html5/"
return
    if (doc-available($url)) then 
        "The URL was well-formed XML. No tidying required. :)"
    else
        let $response := http:send-request(<http:request href="{$url}" method="GET"/>)
        let $response-head := $response[1]
        let $response-body := $response[2]
        return
            if (
                $response-head/http:body/@media-type eq "text/html" 
                and $response-body instance of document-node()
            ) then
                "The URL was an HTML document that was tidied into a " 
                || "well-formed XML document. :) For example: " 
                || $response-body//html:meta => head() => serialize() 
            else
                "The HTTP Client wasn't able to parse the result "
                || "into a well-formed XML document. :("

这将返回:

The URL was an HTML document that was tidied into a well-formed XML document. :) 
For example: 
    <html:meta 
        xmlns:html="http://www.w3.org/1999/xhtml" 
        http-equiv="Content-Type" 
        content="text/html; charset=utf-8"/>

请注意,此<meta>元素是格式良好的XML,由XPath表达式//html:meta生成。 (我在eXist中对此进行了测试。除了表达式为//meta之外,相同的代码也可以在BaseX中工作,因为BaseX不会像eXist那样将整理好的HTML强制进入HTML名称空间。)

我应该补充一点,HTTP客户端规范将其留给处理器来定义“整理”,因此从一个实现到另一个实现肯定会有变化,但是如果问题是“ XPath和XQuery可以在HTML文档上工作吗?”,这表明它们可以并且只能做到与处理器无关的规范,并且在此证明了不同的实现可能对规范的不同理解。

答案 3 :(得分:1)

独立Xpath可以用于html文档。这样做的软件包/模块/应用程序的一些示例

  • 硒驱动器
  • 基于python的lxml(基于libxml2)
  • bash上的xmllint(基于libxml2)

答案 4 :(得分:1)

当我想在HTML文档上使用XPath(比XPath 1.0更高)时,我写了完整的XQuery interpreter for HTML

除了标准的XQuery 3.0外,我还添加了一些可选的扩展名(实际上是不允许的,但对HTML有用),例如不区分大小写地匹配节点名称或使用名称空间更加轻松。