【问题标题】:Transform Javascript XPath in valid PHP query() XPath | normalize JS XPath --> PHP在有效的 PHP query() XPath 中转换 Javascript XPath |规范化 JS XPath --> PHP
【发布时间】:2012-08-01 12:55:42
【问题描述】:

这是 Javascript 中的有效 XPath:

id("priceInfo")/div[@class="standardProdPricingGroup"]/span[1]

这变成了与 DOMXPath 一起使用的有效 PHP XPath->query() 是

//*[@id="priceInfo"]//div[@class="standardProdPricingGroup"]//span[1]
  1. 您知道任何已经进行此转换的库或自定义组件吗?
  2. 您知道列出这两种语法差异的可用文档吗?

我主要担心可能存在很多差异,我正在寻找这些差异,但我在识别这些差异时遇到了问题。

这个问题也可以用不同的方式提出:由于 Javascript 可以有不同的有效 XPath 格式,如何规范它们以与 PHP 一起使用。

其中一个更新还提到,如果存在包含此定义的有效 DTD,则 id() 函数是有效的 XPath。我对输入 DTD 没有控制权,如果有办法找到无需任何特定 DTD 即可工作的解决方案,那就太棒了。

更新:

我想用算法将第一种格式转换为第二种格式。我的输入是第一个而不是第二个。无法更改。

正如@Nison Maël 所指出的,第二种格式是有效的 Javascript XPath,如下所示:http://jsbin.com/elatum/2/edit 不幸的是,这只会增加 Javascript XPath“碎片化”的问题。

@salathe 指出,如果记录的输入具有有效的 DTD(@Dimitre Novatchev 在评论中提到这一点,但忽略了重要性),则有效的 Javascript XPath 查询在 PHP 中可以正常工作。不幸的是,我无法控制输入 DTD,所以现在我必须研究一种方法来克服这个问题,或者找到一个即使没有有效 DTD 也能工作的解决方案。

【问题讨论】:

  • 这是一个很好的问题!看起来那里没有任何文档(至少不是通过粗略的谷歌搜索)。我很高兴看到这个问题的答案。
  • 第一个表达式是合法的 XPath 表达式。但是,要使 Xpath 函数 id() 起作用,XML 必须具有 DTD,并且 DTD 中的元素定义必须具有具有 ID 关键字的属性。
  • @DimitreNovatatchev:那么/// 的翻译呢?
  • @choroba Java 在整个问题中没有被提及一次。此外,id() 是您链接到的规范中提到的 节点集函数
  • 我不认为 javascript 的 xpath 与 php 有很大不同。我的意思是xpath语言应该是一样的,对吧?您能否添加您具体指的是哪个javascript xpath?对于 php,很明显,只有一个。但是等等,不止一个,但你已经写过你指的是标准的 DOMDocument 扩展,对吧。

标签: php javascript xml dom xpath


【解决方案1】:

刚刚看到 Salathe 实际上回答了同样的问题,但考虑到您的评论并更加强调这一点:

您不需要指定任何 DTD。只要您使用DOMDocument::loadHTMLDOMDocument::loadHTMLFile 函数,HTML id 属性实际上是为xpath id() 函数注册的。使用http://jsbin.com/elatum/2/edit 中给出的演示 HTML,您甚至会在加载文档时遇到错误:

警告:DOMDocument::loadHTMLFile(): ID priceInfo 已在...中定义

这已经表明这是一个真正的 ID 属性,因为它抱怨重复。相关示例代码如下所示:

$xpath = 'id("priceInfo")/div[@class="standardProdPricingGroup"]/span[1]';

$doc = new DOMDocument();
$doc->loadHTMLFile(__DIR__ . '/../data/file-11796340.html');
$xp = new DOMXPath($doc);

$r = $xp->query($xpath);
echo $xpath, "\n";
echo $r ? $r->length : 0, ' elements found', "\n";
if (!$r) return;
foreach($r as $node) {
    echo " - ", $node->nodeValue, "\n";
}

输出是:

id("priceInfo")/div[@class="standardProdPricingGroup"]/span[1]
1 elements found
 - hello

如果您需要更多控制,请先运行 xpath 以将所有 HTML id 属性标记为 xpath 的 ID:

$r = $xp->query("//*[@id]");
if ($r) foreach($r as $node) {
    $node->setIdAttribute('id', true);
}

然后您可以使用与 id() 函数相同的 xpath,无需更改它。

【讨论】:

    【解决方案2】:

    您不能在表达式的开头将id("...") 翻译成//*[@id="..."][1] 吗?

    例如,如果可以假设您在 id(...) 表达式中没有任何括号:

    $queryRewritten =   preg_replace('/^id\(([^\)]+)\)/','//*[@id=$1][1]',$query);
    

    Sample code

    编辑:更正了替换,id() 必须是表达式中的第一个

    【讨论】:

    • 它有帮助,但我很好奇未来还会出现什么其他未记录的东西。
    • 这并不是真正的无证资料,XPATH 规范对这种行为非常清楚。未记录的部分是关于浏览器 DOM 引擎隐式地将 Doctype 应用于 HTML DOM。
    • @Pentium10 也许您需要更明确地说明您要实现的目标
    • 正如我更新问题的最后一行所说,我想找到一个独立于 DTD 的解决方案。
    • 除了使用不同命名空间前缀的文档外,这可能会欺骗 wpath 引擎。或为属性指定默认隐含值的 DTD(HTML 绝不应如此)。你应该是安全的
    【解决方案3】:

    这不是一个完整的答案,但它太大而无法作为评论发表,它可能会对您有所帮助。

    如果您可以控制输入 XML,那么您可以通过在 id 属性前加上 xml: 前缀,在 XML 文档本身中显式声明它们,而不是使用 DTD 来声明 id 属性。

    例如,如果你有 XML

    <foo id="x27"/>
    

    改成

    <foo xml:id="x27"/>
    

    那么 id() 函数会将该属性识别为正式的 XML id 类型,而不仅仅是名称为 id 的属性。

    我知道这个“技巧”在 Saxon 处理器上有效,但我必须承认我没有在 PHP 上尝试过。

    W3C xml:id

    【讨论】:

    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 2014-08-16
    • 2018-09-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2012-01-14
    • 2010-10-07
    相关资源
    最近更新 更多